;
+ YmdHMS (timestamp: string, infix: string) : string;
+ }
+
+ /* tslint:disable */
+
+ export class acx extends Exchange {}
+ export class aofex extends Exchange {}
+ export class bcex extends Exchange {}
+ export class bequant extends hitbtc {}
+ export class bibox extends Exchange {}
+ export class bigone extends Exchange {}
+ export class binance extends Exchange {}
+ export class binanceus extends binance {}
+ export class bit2c extends Exchange {}
+ export class bitbank extends Exchange {}
+ export class bitbay extends Exchange {}
+ export class bitcoincom extends hitbtc {}
+ export class bitfinex extends Exchange {}
+ export class bitfinex2 extends bitfinex {}
+ export class bitflyer extends Exchange {}
+ export class bitforex extends Exchange {}
+ export class bitget extends Exchange {}
+ export class bithumb extends Exchange {}
+ export class bitkk extends zb {}
+ export class bitmart extends Exchange {}
+ export class bitmax extends Exchange {}
+ export class bitmex extends Exchange {}
+ export class bitpanda extends Exchange {}
+ export class bitso extends Exchange {}
+ export class bitstamp extends Exchange {}
+ export class bitstamp1 extends Exchange {}
+ export class bittrex extends Exchange {}
+ export class bitvavo extends Exchange {}
+ export class bitz extends Exchange {}
+ export class bl3p extends Exchange {}
+ export class bleutrade extends Exchange {}
+ export class braziliex extends Exchange {}
+ export class btcalpha extends Exchange {}
+ export class btcbox extends Exchange {}
+ export class btcmarkets extends Exchange {}
+ export class btctradeua extends Exchange {}
+ export class btcturk extends Exchange {}
+ export class buda extends Exchange {}
+ export class bw extends Exchange {}
+ export class bybit extends Exchange {}
+ export class bytetrade extends Exchange {}
+ export class cex extends Exchange {}
+ export class chilebit extends foxbit {}
+ export class coinbase extends Exchange {}
+ export class coinbaseprime extends coinbasepro {}
+ export class coinbasepro extends Exchange {}
+ export class coincheck extends Exchange {}
+ export class coinegg extends Exchange {}
+ export class coinex extends Exchange {}
+ export class coinfalcon extends Exchange {}
+ export class coinfloor extends Exchange {}
+ export class coingi extends Exchange {}
+ export class coinmarketcap extends Exchange {}
+ export class coinmate extends Exchange {}
+ export class coinone extends Exchange {}
+ export class coinspot extends Exchange {}
+ export class crex24 extends Exchange {}
+ export class currencycom extends Exchange {}
+ export class deribit extends Exchange {}
+ export class digifinex extends Exchange {}
+ export class dsx extends Exchange {}
+ export class eterbase extends Exchange {}
+ export class exmo extends Exchange {}
+ export class exx extends Exchange {}
+ export class fcoin extends Exchange {}
+ export class fcoinjp extends fcoin {}
+ export class flowbtc extends Exchange {}
+ export class foxbit extends Exchange {}
+ export class ftx extends Exchange {}
+ export class gateio extends Exchange {}
+ export class gemini extends Exchange {}
+ export class hbtc extends Exchange {}
+ export class hitbtc extends Exchange {}
+ export class hollaex extends Exchange {}
+ export class huobijp extends huobipro {}
+ export class huobipro extends Exchange {}
+ export class huobiru extends huobipro {}
+ export class ice3x extends Exchange {}
+ export class idex extends Exchange {}
+ export class independentreserve extends Exchange {}
+ export class indodax extends Exchange {}
+ export class itbit extends Exchange {}
+ export class kraken extends Exchange {}
+ export class kucoin extends Exchange {}
+ export class kuna extends acx {}
+ export class lakebtc extends Exchange {}
+ export class latoken extends Exchange {}
+ export class lbank extends Exchange {}
+ export class liquid extends Exchange {}
+ export class livecoin extends Exchange {}
+ export class luno extends Exchange {}
+ export class lykke extends Exchange {}
+ export class mercado extends Exchange {}
+ export class mixcoins extends Exchange {}
+ export class novadax extends Exchange {}
+ export class oceanex extends Exchange {}
+ export class okcoin extends okex {}
+ export class okex extends Exchange {}
+ export class paymium extends Exchange {}
+ export class phemex extends Exchange {}
+ export class poloniex extends Exchange {}
+ export class probit extends Exchange {}
+ export class qtrade extends Exchange {}
+ export class rightbtc extends Exchange {}
+ export class ripio extends Exchange {}
+ export class southxchange extends Exchange {}
+ export class stex extends Exchange {}
+ export class surbitcoin extends foxbit {}
+ export class therock extends Exchange {}
+ export class tidebit extends Exchange {}
+ export class tidex extends Exchange {}
+ export class timex extends Exchange {}
+ export class upbit extends Exchange {}
+ export class vaultoro extends Exchange {}
+ export class vbtc extends foxbit {}
+ export class vcc extends Exchange {}
+ export class wavesexchange extends Exchange {}
+ export class whitebit extends Exchange {}
+ export class xbtce extends Exchange {}
+ export class xena extends Exchange {}
+ export class yobit extends Exchange {}
+ export class zaif extends Exchange {}
+ export class zb extends Exchange {}
+
+ /* tslint:enable */
+
+}
diff --git a/TaskServer/node_modules/ccxt/ccxt.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/ccxt.js
similarity index 89%
rename from TaskServer/node_modules/ccxt/ccxt.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/ccxt.js
index d6ed88a1f..ca416bfae 100644
--- a/TaskServer/node_modules/ccxt/ccxt.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/ccxt.js
@@ -35,40 +35,41 @@ const Exchange = require ('./js/base/Exchange')
//-----------------------------------------------------------------------------
// this is updated by vss.js when building
-const version = '1.27.45'
+const version = '1.38.75'
Exchange.ccxtVersion = version
//-----------------------------------------------------------------------------
const exchanges = {
- '_1btcxe': require ('./js/_1btcxe.js'),
'acx': require ('./js/acx.js'),
- 'anxpro': require ('./js/anxpro.js'),
'aofex': require ('./js/aofex.js'),
'bcex': require ('./js/bcex.js'),
'bequant': require ('./js/bequant.js'),
'bibox': require ('./js/bibox.js'),
'bigone': require ('./js/bigone.js'),
'binance': require ('./js/binance.js'),
- 'binanceje': require ('./js/binanceje.js'),
'binanceus': require ('./js/binanceus.js'),
'bit2c': require ('./js/bit2c.js'),
'bitbank': require ('./js/bitbank.js'),
'bitbay': require ('./js/bitbay.js'),
+ 'bitcoincom': require ('./js/bitcoincom.js'),
'bitfinex': require ('./js/bitfinex.js'),
'bitfinex2': require ('./js/bitfinex2.js'),
'bitflyer': require ('./js/bitflyer.js'),
'bitforex': require ('./js/bitforex.js'),
+ 'bitget': require ('./js/bitget.js'),
'bithumb': require ('./js/bithumb.js'),
'bitkk': require ('./js/bitkk.js'),
'bitmart': require ('./js/bitmart.js'),
'bitmax': require ('./js/bitmax.js'),
'bitmex': require ('./js/bitmex.js'),
+ 'bitpanda': require ('./js/bitpanda.js'),
'bitso': require ('./js/bitso.js'),
'bitstamp': require ('./js/bitstamp.js'),
'bitstamp1': require ('./js/bitstamp1.js'),
'bittrex': require ('./js/bittrex.js'),
+ 'bitvavo': require ('./js/bitvavo.js'),
'bitz': require ('./js/bitz.js'),
'bl3p': require ('./js/bl3p.js'),
'bleutrade': require ('./js/bleutrade.js'),
@@ -76,7 +77,6 @@ const exchanges = {
'btcalpha': require ('./js/btcalpha.js'),
'btcbox': require ('./js/btcbox.js'),
'btcmarkets': require ('./js/btcmarkets.js'),
- 'btctradeim': require ('./js/btctradeim.js'),
'btctradeua': require ('./js/btctradeua.js'),
'btcturk': require ('./js/btcturk.js'),
'buda': require ('./js/buda.js'),
@@ -98,12 +98,12 @@ const exchanges = {
'coinmate': require ('./js/coinmate.js'),
'coinone': require ('./js/coinone.js'),
'coinspot': require ('./js/coinspot.js'),
- 'coolcoin': require ('./js/coolcoin.js'),
- 'coss': require ('./js/coss.js'),
'crex24': require ('./js/crex24.js'),
+ 'currencycom': require ('./js/currencycom.js'),
'deribit': require ('./js/deribit.js'),
'digifinex': require ('./js/digifinex.js'),
'dsx': require ('./js/dsx.js'),
+ 'eterbase': require ('./js/eterbase.js'),
'exmo': require ('./js/exmo.js'),
'exx': require ('./js/exx.js'),
'fcoin': require ('./js/fcoin.js'),
@@ -111,12 +111,12 @@ const exchanges = {
'flowbtc': require ('./js/flowbtc.js'),
'foxbit': require ('./js/foxbit.js'),
'ftx': require ('./js/ftx.js'),
- 'fybse': require ('./js/fybse.js'),
'gateio': require ('./js/gateio.js'),
'gemini': require ('./js/gemini.js'),
'hbtc': require ('./js/hbtc.js'),
'hitbtc': require ('./js/hitbtc.js'),
'hollaex': require ('./js/hollaex.js'),
+ 'huobijp': require ('./js/huobijp.js'),
'huobipro': require ('./js/huobipro.js'),
'huobiru': require ('./js/huobiru.js'),
'ice3x': require ('./js/ice3x.js'),
@@ -124,7 +124,6 @@ const exchanges = {
'independentreserve': require ('./js/independentreserve.js'),
'indodax': require ('./js/indodax.js'),
'itbit': require ('./js/itbit.js'),
- 'kkex': require ('./js/kkex.js'),
'kraken': require ('./js/kraken.js'),
'kucoin': require ('./js/kucoin.js'),
'kuna': require ('./js/kuna.js'),
@@ -137,27 +136,32 @@ const exchanges = {
'lykke': require ('./js/lykke.js'),
'mercado': require ('./js/mercado.js'),
'mixcoins': require ('./js/mixcoins.js'),
+ 'novadax': require ('./js/novadax.js'),
'oceanex': require ('./js/oceanex.js'),
'okcoin': require ('./js/okcoin.js'),
'okex': require ('./js/okex.js'),
'paymium': require ('./js/paymium.js'),
+ 'phemex': require ('./js/phemex.js'),
'poloniex': require ('./js/poloniex.js'),
+ 'probit': require ('./js/probit.js'),
+ 'qtrade': require ('./js/qtrade.js'),
'rightbtc': require ('./js/rightbtc.js'),
+ 'ripio': require ('./js/ripio.js'),
'southxchange': require ('./js/southxchange.js'),
'stex': require ('./js/stex.js'),
- 'stronghold': require ('./js/stronghold.js'),
'surbitcoin': require ('./js/surbitcoin.js'),
- 'theocean': require ('./js/theocean.js'),
'therock': require ('./js/therock.js'),
'tidebit': require ('./js/tidebit.js'),
'tidex': require ('./js/tidex.js'),
'timex': require ('./js/timex.js'),
- 'topq': require ('./js/topq.js'),
'upbit': require ('./js/upbit.js'),
'vaultoro': require ('./js/vaultoro.js'),
'vbtc': require ('./js/vbtc.js'),
+ 'vcc': require ('./js/vcc.js'),
+ 'wavesexchange': require ('./js/wavesexchange.js'),
'whitebit': require ('./js/whitebit.js'),
'xbtce': require ('./js/xbtce.js'),
+ 'xena': require ('./js/xena.js'),
'yobit': require ('./js/yobit.js'),
'zaif': require ('./js/zaif.js'),
'zb': require ('./js/zb.js'),
diff --git a/TaskServer/node_modules/ccxt/dist/ccxt.browser.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/dist/ccxt.browser.js
similarity index 76%
rename from TaskServer/node_modules/ccxt/dist/ccxt.browser.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/dist/ccxt.browser.js
index acbb6ec4f..6e6c398a4 100644
--- a/TaskServer/node_modules/ccxt/dist/ccxt.browser.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/dist/ccxt.browser.js
@@ -43,40 +43,41 @@ const Exchange = require ('./js/base/Exchange')
//-----------------------------------------------------------------------------
// this is updated by vss.js when building
-const version = '1.27.45'
+const version = '1.38.75'
Exchange.ccxtVersion = version
//-----------------------------------------------------------------------------
const exchanges = {
- '_1btcxe': require ('./js/_1btcxe.js'),
'acx': require ('./js/acx.js'),
- 'anxpro': require ('./js/anxpro.js'),
'aofex': require ('./js/aofex.js'),
'bcex': require ('./js/bcex.js'),
'bequant': require ('./js/bequant.js'),
'bibox': require ('./js/bibox.js'),
'bigone': require ('./js/bigone.js'),
'binance': require ('./js/binance.js'),
- 'binanceje': require ('./js/binanceje.js'),
'binanceus': require ('./js/binanceus.js'),
'bit2c': require ('./js/bit2c.js'),
'bitbank': require ('./js/bitbank.js'),
'bitbay': require ('./js/bitbay.js'),
+ 'bitcoincom': require ('./js/bitcoincom.js'),
'bitfinex': require ('./js/bitfinex.js'),
'bitfinex2': require ('./js/bitfinex2.js'),
'bitflyer': require ('./js/bitflyer.js'),
'bitforex': require ('./js/bitforex.js'),
+ 'bitget': require ('./js/bitget.js'),
'bithumb': require ('./js/bithumb.js'),
'bitkk': require ('./js/bitkk.js'),
'bitmart': require ('./js/bitmart.js'),
'bitmax': require ('./js/bitmax.js'),
'bitmex': require ('./js/bitmex.js'),
+ 'bitpanda': require ('./js/bitpanda.js'),
'bitso': require ('./js/bitso.js'),
'bitstamp': require ('./js/bitstamp.js'),
'bitstamp1': require ('./js/bitstamp1.js'),
'bittrex': require ('./js/bittrex.js'),
+ 'bitvavo': require ('./js/bitvavo.js'),
'bitz': require ('./js/bitz.js'),
'bl3p': require ('./js/bl3p.js'),
'bleutrade': require ('./js/bleutrade.js'),
@@ -84,7 +85,6 @@ const exchanges = {
'btcalpha': require ('./js/btcalpha.js'),
'btcbox': require ('./js/btcbox.js'),
'btcmarkets': require ('./js/btcmarkets.js'),
- 'btctradeim': require ('./js/btctradeim.js'),
'btctradeua': require ('./js/btctradeua.js'),
'btcturk': require ('./js/btcturk.js'),
'buda': require ('./js/buda.js'),
@@ -106,12 +106,12 @@ const exchanges = {
'coinmate': require ('./js/coinmate.js'),
'coinone': require ('./js/coinone.js'),
'coinspot': require ('./js/coinspot.js'),
- 'coolcoin': require ('./js/coolcoin.js'),
- 'coss': require ('./js/coss.js'),
'crex24': require ('./js/crex24.js'),
+ 'currencycom': require ('./js/currencycom.js'),
'deribit': require ('./js/deribit.js'),
'digifinex': require ('./js/digifinex.js'),
'dsx': require ('./js/dsx.js'),
+ 'eterbase': require ('./js/eterbase.js'),
'exmo': require ('./js/exmo.js'),
'exx': require ('./js/exx.js'),
'fcoin': require ('./js/fcoin.js'),
@@ -119,12 +119,12 @@ const exchanges = {
'flowbtc': require ('./js/flowbtc.js'),
'foxbit': require ('./js/foxbit.js'),
'ftx': require ('./js/ftx.js'),
- 'fybse': require ('./js/fybse.js'),
'gateio': require ('./js/gateio.js'),
'gemini': require ('./js/gemini.js'),
'hbtc': require ('./js/hbtc.js'),
'hitbtc': require ('./js/hitbtc.js'),
'hollaex': require ('./js/hollaex.js'),
+ 'huobijp': require ('./js/huobijp.js'),
'huobipro': require ('./js/huobipro.js'),
'huobiru': require ('./js/huobiru.js'),
'ice3x': require ('./js/ice3x.js'),
@@ -132,7 +132,6 @@ const exchanges = {
'independentreserve': require ('./js/independentreserve.js'),
'indodax': require ('./js/indodax.js'),
'itbit': require ('./js/itbit.js'),
- 'kkex': require ('./js/kkex.js'),
'kraken': require ('./js/kraken.js'),
'kucoin': require ('./js/kucoin.js'),
'kuna': require ('./js/kuna.js'),
@@ -145,27 +144,32 @@ const exchanges = {
'lykke': require ('./js/lykke.js'),
'mercado': require ('./js/mercado.js'),
'mixcoins': require ('./js/mixcoins.js'),
+ 'novadax': require ('./js/novadax.js'),
'oceanex': require ('./js/oceanex.js'),
'okcoin': require ('./js/okcoin.js'),
'okex': require ('./js/okex.js'),
'paymium': require ('./js/paymium.js'),
+ 'phemex': require ('./js/phemex.js'),
'poloniex': require ('./js/poloniex.js'),
+ 'probit': require ('./js/probit.js'),
+ 'qtrade': require ('./js/qtrade.js'),
'rightbtc': require ('./js/rightbtc.js'),
+ 'ripio': require ('./js/ripio.js'),
'southxchange': require ('./js/southxchange.js'),
'stex': require ('./js/stex.js'),
- 'stronghold': require ('./js/stronghold.js'),
'surbitcoin': require ('./js/surbitcoin.js'),
- 'theocean': require ('./js/theocean.js'),
'therock': require ('./js/therock.js'),
'tidebit': require ('./js/tidebit.js'),
'tidex': require ('./js/tidex.js'),
'timex': require ('./js/timex.js'),
- 'topq': require ('./js/topq.js'),
'upbit': require ('./js/upbit.js'),
'vaultoro': require ('./js/vaultoro.js'),
'vbtc': require ('./js/vbtc.js'),
+ 'vcc': require ('./js/vcc.js'),
+ 'wavesexchange': require ('./js/wavesexchange.js'),
'whitebit': require ('./js/whitebit.js'),
'xbtce': require ('./js/xbtce.js'),
+ 'xena': require ('./js/xena.js'),
'yobit': require ('./js/yobit.js'),
'zaif': require ('./js/zaif.js'),
'zb': require ('./js/zb.js'),
@@ -177,314 +181,7 @@ module.exports = Object.assign ({ version, Exchange, 'exchanges': Object.keys (e
//-----------------------------------------------------------------------------
-},{"./js/_1btcxe.js":3,"./js/acx.js":4,"./js/anxpro.js":5,"./js/aofex.js":6,"./js/base/Exchange":7,"./js/base/errors":9,"./js/base/functions":10,"./js/bcex.js":21,"./js/bequant.js":22,"./js/bibox.js":23,"./js/bigone.js":24,"./js/binance.js":25,"./js/binanceje.js":26,"./js/binanceus.js":27,"./js/bit2c.js":28,"./js/bitbank.js":29,"./js/bitbay.js":30,"./js/bitfinex.js":31,"./js/bitfinex2.js":32,"./js/bitflyer.js":33,"./js/bitforex.js":34,"./js/bithumb.js":35,"./js/bitkk.js":36,"./js/bitmart.js":37,"./js/bitmax.js":38,"./js/bitmex.js":39,"./js/bitso.js":40,"./js/bitstamp.js":41,"./js/bitstamp1.js":42,"./js/bittrex.js":43,"./js/bitz.js":44,"./js/bl3p.js":45,"./js/bleutrade.js":46,"./js/braziliex.js":47,"./js/btcalpha.js":48,"./js/btcbox.js":49,"./js/btcmarkets.js":50,"./js/btctradeim.js":51,"./js/btctradeua.js":52,"./js/btcturk.js":53,"./js/buda.js":54,"./js/bw.js":55,"./js/bybit.js":56,"./js/bytetrade.js":57,"./js/cex.js":58,"./js/chilebit.js":59,"./js/coinbase.js":60,"./js/coinbaseprime.js":61,"./js/coinbasepro.js":62,"./js/coincheck.js":63,"./js/coinegg.js":64,"./js/coinex.js":65,"./js/coinfalcon.js":66,"./js/coinfloor.js":67,"./js/coingi.js":68,"./js/coinmarketcap.js":69,"./js/coinmate.js":70,"./js/coinone.js":71,"./js/coinspot.js":72,"./js/coolcoin.js":73,"./js/coss.js":74,"./js/crex24.js":75,"./js/deribit.js":76,"./js/digifinex.js":77,"./js/dsx.js":78,"./js/exmo.js":79,"./js/exx.js":80,"./js/fcoin.js":81,"./js/fcoinjp.js":82,"./js/flowbtc.js":83,"./js/foxbit.js":84,"./js/ftx.js":85,"./js/fybse.js":86,"./js/gateio.js":87,"./js/gemini.js":88,"./js/hbtc.js":89,"./js/hitbtc.js":90,"./js/hollaex.js":91,"./js/huobipro.js":92,"./js/huobiru.js":93,"./js/ice3x.js":94,"./js/idex.js":95,"./js/independentreserve.js":96,"./js/indodax.js":97,"./js/itbit.js":98,"./js/kkex.js":99,"./js/kraken.js":100,"./js/kucoin.js":101,"./js/kuna.js":102,"./js/lakebtc.js":103,"./js/latoken.js":104,"./js/lbank.js":105,"./js/liquid.js":106,"./js/livecoin.js":107,"./js/luno.js":108,"./js/lykke.js":109,"./js/mercado.js":110,"./js/mixcoins.js":111,"./js/oceanex.js":112,"./js/okcoin.js":113,"./js/okex.js":114,"./js/paymium.js":115,"./js/poloniex.js":116,"./js/rightbtc.js":117,"./js/southxchange.js":118,"./js/stex.js":156,"./js/stronghold.js":157,"./js/surbitcoin.js":158,"./js/theocean.js":159,"./js/therock.js":160,"./js/tidebit.js":161,"./js/tidex.js":162,"./js/timex.js":163,"./js/topq.js":164,"./js/upbit.js":165,"./js/vaultoro.js":166,"./js/vbtc.js":167,"./js/whitebit.js":168,"./js/xbtce.js":169,"./js/yobit.js":170,"./js/zaif.js":171,"./js/zb.js":172}],3:[function(require,module,exports){
-'use strict';
-
-// ---------------------------------------------------------------------------
-
-const Exchange = require ('./base/Exchange');
-const { ExchangeError, ExchangeNotAvailable } = require ('./base/errors');
-
-// ---------------------------------------------------------------------------
-
-module.exports = class _1btcxe extends Exchange {
- describe () {
- return this.deepExtend (super.describe (), {
- 'id': '_1btcxe',
- 'name': '1BTCXE',
- 'countries': [ 'PA' ], // Panama
- 'comment': 'Crypto Capital API',
- 'has': {
- 'CORS': true,
- 'withdraw': true,
- },
- 'timeframes': {
- '1d': '1year',
- },
- 'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27766049-2b294408-5ecc-11e7-85cc-adaff013dc1a.jpg',
- 'api': 'https://1btcxe.com/api',
- 'www': 'https://1btcxe.com',
- 'doc': 'https://1btcxe.com/api-docs.php',
- },
- 'api': {
- 'public': {
- 'get': [
- 'stats',
- 'historical-prices',
- 'order-book',
- 'transactions',
- ],
- },
- 'private': {
- 'post': [
- 'balances-and-info',
- 'open-orders',
- 'user-transactions',
- 'btc-deposit-address/get',
- 'btc-deposit-address/new',
- 'deposits/get',
- 'withdrawals/get',
- 'orders/new',
- 'orders/edit',
- 'orders/cancel',
- 'orders/status',
- 'withdrawals/new',
- ],
- },
- },
- });
- }
-
- async fetchMarkets (params = {}) {
- return [
- { 'id': 'USD', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD', 'baseId': 'BTC', 'quoteId': 'USD' },
- { 'id': 'EUR', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'BTC', 'quoteId': 'EUR' },
- { 'id': 'CNY', 'symbol': 'BTC/CNY', 'base': 'BTC', 'quote': 'CNY', 'baseId': 'BTC', 'quoteId': 'CNY' },
- { 'id': 'RUB', 'symbol': 'BTC/RUB', 'base': 'BTC', 'quote': 'RUB', 'baseId': 'BTC', 'quoteId': 'RUB' },
- { 'id': 'CHF', 'symbol': 'BTC/CHF', 'base': 'BTC', 'quote': 'CHF', 'baseId': 'BTC', 'quoteId': 'CHF' },
- { 'id': 'JPY', 'symbol': 'BTC/JPY', 'base': 'BTC', 'quote': 'JPY', 'baseId': 'BTC', 'quoteId': 'JPY' },
- { 'id': 'GBP', 'symbol': 'BTC/GBP', 'base': 'BTC', 'quote': 'GBP', 'baseId': 'BTC', 'quoteId': 'GBP' },
- { 'id': 'CAD', 'symbol': 'BTC/CAD', 'base': 'BTC', 'quote': 'CAD', 'baseId': 'BTC', 'quoteId': 'CAD' },
- { 'id': 'AUD', 'symbol': 'BTC/AUD', 'base': 'BTC', 'quote': 'AUD', 'baseId': 'BTC', 'quoteId': 'AUD' },
- { 'id': 'AED', 'symbol': 'BTC/AED', 'base': 'BTC', 'quote': 'AED', 'baseId': 'BTC', 'quoteId': 'AED' },
- { 'id': 'BGN', 'symbol': 'BTC/BGN', 'base': 'BTC', 'quote': 'BGN', 'baseId': 'BTC', 'quoteId': 'BGN' },
- { 'id': 'CZK', 'symbol': 'BTC/CZK', 'base': 'BTC', 'quote': 'CZK', 'baseId': 'BTC', 'quoteId': 'CZK' },
- { 'id': 'DKK', 'symbol': 'BTC/DKK', 'base': 'BTC', 'quote': 'DKK', 'baseId': 'BTC', 'quoteId': 'DKK' },
- { 'id': 'HKD', 'symbol': 'BTC/HKD', 'base': 'BTC', 'quote': 'HKD', 'baseId': 'BTC', 'quoteId': 'HKD' },
- { 'id': 'HRK', 'symbol': 'BTC/HRK', 'base': 'BTC', 'quote': 'HRK', 'baseId': 'BTC', 'quoteId': 'HRK' },
- { 'id': 'HUF', 'symbol': 'BTC/HUF', 'base': 'BTC', 'quote': 'HUF', 'baseId': 'BTC', 'quoteId': 'HUF' },
- { 'id': 'ILS', 'symbol': 'BTC/ILS', 'base': 'BTC', 'quote': 'ILS', 'baseId': 'BTC', 'quoteId': 'ILS' },
- { 'id': 'INR', 'symbol': 'BTC/INR', 'base': 'BTC', 'quote': 'INR', 'baseId': 'BTC', 'quoteId': 'INR' },
- { 'id': 'MUR', 'symbol': 'BTC/MUR', 'base': 'BTC', 'quote': 'MUR', 'baseId': 'BTC', 'quoteId': 'MUR' },
- { 'id': 'MXN', 'symbol': 'BTC/MXN', 'base': 'BTC', 'quote': 'MXN', 'baseId': 'BTC', 'quoteId': 'MXN' },
- { 'id': 'NOK', 'symbol': 'BTC/NOK', 'base': 'BTC', 'quote': 'NOK', 'baseId': 'BTC', 'quoteId': 'NOK' },
- { 'id': 'NZD', 'symbol': 'BTC/NZD', 'base': 'BTC', 'quote': 'NZD', 'baseId': 'BTC', 'quoteId': 'NZD' },
- { 'id': 'PLN', 'symbol': 'BTC/PLN', 'base': 'BTC', 'quote': 'PLN', 'baseId': 'BTC', 'quoteId': 'PLN' },
- { 'id': 'RON', 'symbol': 'BTC/RON', 'base': 'BTC', 'quote': 'RON', 'baseId': 'BTC', 'quoteId': 'RON' },
- { 'id': 'SEK', 'symbol': 'BTC/SEK', 'base': 'BTC', 'quote': 'SEK', 'baseId': 'BTC', 'quoteId': 'SEK' },
- { 'id': 'SGD', 'symbol': 'BTC/SGD', 'base': 'BTC', 'quote': 'SGD', 'baseId': 'BTC', 'quoteId': 'SGD' },
- { 'id': 'THB', 'symbol': 'BTC/THB', 'base': 'BTC', 'quote': 'THB', 'baseId': 'BTC', 'quoteId': 'THB' },
- { 'id': 'TRY', 'symbol': 'BTC/TRY', 'base': 'BTC', 'quote': 'TRY', 'baseId': 'BTC', 'quoteId': 'TRY' },
- { 'id': 'ZAR', 'symbol': 'BTC/ZAR', 'base': 'BTC', 'quote': 'ZAR', 'baseId': 'BTC', 'quoteId': 'ZAR' },
- ];
- }
-
- async fetchBalance (params = {}) {
- await this.loadMarkets ();
- const response = await this.privatePostBalancesAndInfo (params);
- const balance = response['balances-and-info'];
- const result = { 'info': balance };
- const codes = Object.keys (this.currencies);
- for (let i = 0; i < codes.length; i++) {
- const code = codes[i];
- const currency = this.currency (code);
- const currencyId = currency['id'];
- const account = this.account ();
- account['free'] = this.safeFloat (balance['available'], currencyId);
- account['used'] = this.safeFloat (balance['on_hold'], currencyId);
- result[code] = account;
- }
- return this.parseBalance (result);
- }
-
- async fetchOrderBook (symbol, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'currency': this.marketId (symbol),
- };
- const response = await this.publicGetOrderBook (this.extend (request, params));
- return this.parseOrderBook (response['order-book'], undefined, 'bid', 'ask', 'price', 'order_amount');
- }
-
- async fetchTicker (symbol, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'currency': this.marketId (symbol),
- };
- const response = await this.publicGetStats (this.extend (request, params));
- const ticker = this.safeValue (response, 'stats', {});
- const last = this.safeFloat (ticker, 'last_price');
- return {
- 'symbol': symbol,
- 'timestamp': undefined,
- 'datetime': undefined,
- 'high': this.safeFloat (ticker, 'max'),
- 'low': this.safeFloat (ticker, 'min'),
- 'bid': this.safeFloat (ticker, 'bid'),
- 'bidVolume': undefined,
- 'ask': this.safeFloat (ticker, 'ask'),
- 'askVolume': undefined,
- 'vwap': undefined,
- 'open': this.safeFloat (ticker, 'open'),
- 'close': last,
- 'last': last,
- 'previousClose': undefined,
- 'change': this.safeFloat (ticker, 'daily_change'),
- 'percentage': undefined,
- 'average': undefined,
- 'baseVolume': undefined,
- 'quoteVolume': this.safeFloat (ticker, 'total_btc_traded'),
- 'info': ticker,
- };
- }
-
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
- return [
- this.parse8601 (ohlcv['date'] + ' 00:00:00'),
- undefined,
- undefined,
- undefined,
- this.safeFloat (ohlcv, 'price'),
- undefined,
- ];
- }
-
- async fetchOHLCV (symbol, timeframe = '1d', since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const response = await this.publicGetHistoricalPrices (this.extend ({
- 'currency': market['id'],
- 'timeframe': this.timeframes[timeframe],
- }, params));
- const ohlcvs = this.toArray (this.omit (response['historical-prices'], 'request_currency'));
- return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
- }
-
- parseTrade (trade, market = undefined) {
- const timestamp = this.safeTimestamp (trade, 'timestamp');
- const id = this.safeString (trade, 'id');
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- const type = undefined;
- const side = this.safeString (trade, 'maker_type');
- const price = this.safeFloat (trade, 'price');
- const amount = this.safeFloat (trade, 'amount');
- let cost = undefined;
- if (amount !== undefined) {
- if (price !== undefined) {
- cost = amount * price;
- }
- }
- return {
- 'id': id,
- 'info': trade,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'symbol': symbol,
- 'order': undefined,
- 'type': type,
- 'side': side,
- 'takerOrMaker': undefined,
- 'price': price,
- 'amount': amount,
- 'cost': cost,
- 'fee': undefined,
- };
- }
-
- async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'currency': market['id'],
- };
- if (limit !== undefined) {
- request['limit'] = limit;
- }
- const response = await this.publicGetTransactions (this.extend (request, params));
- const trades = this.toArray (this.omit (response['transactions'], 'request_currency'));
- return this.parseTrades (trades, market, since, limit);
- }
-
- async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'side': side,
- 'type': type,
- 'currency': this.marketId (symbol),
- 'amount': amount,
- };
- if (type === 'limit') {
- request['limit_price'] = price;
- }
- const result = await this.privatePostOrdersNew (this.extend (request, params));
- return {
- 'info': result,
- 'id': result,
- };
- }
-
- async cancelOrder (id, symbol = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'id': id,
- };
- return await this.privatePostOrdersCancel (this.extend (request, params));
- }
-
- async withdraw (code, amount, address, tag = undefined, params = {}) {
- this.checkAddress (address);
- await this.loadMarkets ();
- const currency = this.currency (code);
- const request = {
- 'currency': currency['id'],
- 'amount': parseFloat (amount),
- 'address': address,
- };
- const response = await this.privatePostWithdrawalsNew (this.extend (request, params));
- return {
- 'info': response,
- 'id': response['result']['uuid'],
- };
- }
-
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- if (this.id === 'cryptocapital') {
- throw new ExchangeError (this.id + ' is an abstract base API for _1btcxe');
- }
- let url = this.urls['api'] + '/' + path;
- if (api === 'public') {
- if (Object.keys (params).length) {
- url += '?' + this.urlencode (params);
- }
- } else {
- this.checkRequiredCredentials ();
- const query = this.extend ({
- 'api_key': this.apiKey,
- 'nonce': this.nonce (),
- }, params);
- const request = this.json (query);
- query['signature'] = this.hmac (this.encode (request), this.encode (this.secret));
- body = this.json (query);
- headers = { 'Content-Type': 'application/json' };
- }
- return { 'url': url, 'method': method, 'body': body, 'headers': headers };
- }
-
- async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- const response = await this.fetch2 (path, api, method, params, headers, body);
- if (typeof response === 'string') {
- if (response.indexOf ('Maintenance') >= 0) {
- throw new ExchangeNotAvailable (this.id + ' on maintenance');
- }
- }
- if ('errors' in response) {
- let errors = [];
- for (let e = 0; e < response['errors'].length; e++) {
- const error = response['errors'][e];
- errors.push (error['code'] + ': ' + error['message']);
- }
- errors = errors.join (' ');
- throw new ExchangeError (this.id + ' ' + errors);
- }
- return response;
- }
-};
-
-},{"./base/Exchange":7,"./base/errors":9}],4:[function(require,module,exports){
+},{"./js/acx.js":3,"./js/aofex.js":4,"./js/base/Exchange":5,"./js/base/errors":7,"./js/base/functions":8,"./js/bcex.js":19,"./js/bequant.js":20,"./js/bibox.js":21,"./js/bigone.js":22,"./js/binance.js":23,"./js/binanceus.js":24,"./js/bit2c.js":25,"./js/bitbank.js":26,"./js/bitbay.js":27,"./js/bitcoincom.js":28,"./js/bitfinex.js":29,"./js/bitfinex2.js":30,"./js/bitflyer.js":31,"./js/bitforex.js":32,"./js/bitget.js":33,"./js/bithumb.js":34,"./js/bitkk.js":35,"./js/bitmart.js":36,"./js/bitmax.js":37,"./js/bitmex.js":38,"./js/bitpanda.js":39,"./js/bitso.js":40,"./js/bitstamp.js":41,"./js/bitstamp1.js":42,"./js/bittrex.js":43,"./js/bitvavo.js":44,"./js/bitz.js":45,"./js/bl3p.js":46,"./js/bleutrade.js":47,"./js/braziliex.js":48,"./js/btcalpha.js":49,"./js/btcbox.js":50,"./js/btcmarkets.js":51,"./js/btctradeua.js":52,"./js/btcturk.js":53,"./js/buda.js":54,"./js/bw.js":55,"./js/bybit.js":56,"./js/bytetrade.js":57,"./js/cex.js":58,"./js/chilebit.js":59,"./js/coinbase.js":60,"./js/coinbaseprime.js":61,"./js/coinbasepro.js":62,"./js/coincheck.js":63,"./js/coinegg.js":64,"./js/coinex.js":65,"./js/coinfalcon.js":66,"./js/coinfloor.js":67,"./js/coingi.js":68,"./js/coinmarketcap.js":69,"./js/coinmate.js":70,"./js/coinone.js":71,"./js/coinspot.js":72,"./js/crex24.js":73,"./js/currencycom.js":74,"./js/deribit.js":75,"./js/digifinex.js":76,"./js/dsx.js":77,"./js/eterbase.js":78,"./js/exmo.js":79,"./js/exx.js":80,"./js/fcoin.js":81,"./js/fcoinjp.js":82,"./js/flowbtc.js":83,"./js/foxbit.js":84,"./js/ftx.js":85,"./js/gateio.js":86,"./js/gemini.js":87,"./js/hbtc.js":88,"./js/hitbtc.js":89,"./js/hollaex.js":90,"./js/huobijp.js":91,"./js/huobipro.js":92,"./js/huobiru.js":93,"./js/ice3x.js":94,"./js/idex.js":95,"./js/independentreserve.js":96,"./js/indodax.js":97,"./js/itbit.js":98,"./js/kraken.js":99,"./js/kucoin.js":100,"./js/kuna.js":101,"./js/lakebtc.js":102,"./js/latoken.js":103,"./js/lbank.js":104,"./js/liquid.js":105,"./js/livecoin.js":106,"./js/luno.js":107,"./js/lykke.js":108,"./js/mercado.js":109,"./js/mixcoins.js":110,"./js/novadax.js":111,"./js/oceanex.js":112,"./js/okcoin.js":113,"./js/okex.js":114,"./js/paymium.js":115,"./js/phemex.js":116,"./js/poloniex.js":117,"./js/probit.js":118,"./js/qtrade.js":119,"./js/rightbtc.js":120,"./js/ripio.js":121,"./js/southxchange.js":122,"./js/stex.js":163,"./js/surbitcoin.js":164,"./js/therock.js":165,"./js/tidebit.js":166,"./js/tidex.js":167,"./js/timex.js":168,"./js/upbit.js":169,"./js/vaultoro.js":170,"./js/vbtc.js":171,"./js/vcc.js":172,"./js/wavesexchange.js":173,"./js/whitebit.js":174,"./js/xbtce.js":175,"./js/xena.js":176,"./js/yobit.js":177,"./js/zaif.js":178,"./js/zb.js":179}],3:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -503,11 +200,19 @@ module.exports = class acx extends Exchange {
'rateLimit': 1000,
'version': 'v2',
'has': {
+ 'cancelOrder': true,
'CORS': true,
- 'fetchTickers': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchOHLCV': true,
- 'withdraw': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1',
@@ -714,7 +419,7 @@ module.exports = class acx extends Exchange {
}
result[symbol] = this.parseTicker (response[id], market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -751,6 +456,14 @@ module.exports = class acx extends Exchange {
};
}
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTimestamp (params);
+ //
+ // 1594911427
+ //
+ return response * 1000;
+ }
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -761,14 +474,14 @@ module.exports = class acx extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
return [
- ohlcv[0] * 1000,
- ohlcv[1],
- ohlcv[2],
- ohlcv[3],
- ohlcv[4],
- ohlcv[5],
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -800,13 +513,8 @@ module.exports = class acx extends Exchange {
}
parseOrder (order, market = undefined) {
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- } else {
- const marketId = this.safeString (order, 'market');
- symbol = this.markets_by_id[marketId]['symbol'];
- }
+ const marketId = this.safeString (order, 'market');
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const status = this.parseOrderStatus (this.safeString (order, 'state'));
const type = this.safeString (order, 'type');
@@ -821,8 +529,10 @@ module.exports = class acx extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': this.safeFloat (order, 'price'),
+ 'stopPrice': undefined,
'amount': this.safeFloat (order, 'volume'),
'filled': this.safeFloat (order, 'executed_volume'),
'remaining': this.safeFloat (order, 'remaining_volume'),
@@ -959,1230 +669,7 @@ module.exports = class acx extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],5:[function(require,module,exports){
-'use strict';
-
-// ---------------------------------------------------------------------------
-
-const Exchange = require ('./base/Exchange');
-const { ExchangeError, AuthenticationError, InsufficientFunds, ExchangeNotAvailable, InvalidOrder, BadRequest, OrderNotFound, NotSupported } = require ('./base/errors');
-
-// ---------------------------------------------------------------------------
-
-module.exports = class anxpro extends Exchange {
- describe () {
- return this.deepExtend (super.describe (), {
- 'id': 'anxpro',
- 'name': 'ANXPro',
- 'countries': [ 'JP', 'SG', 'HK', 'NZ' ],
- 'rateLimit': 1500,
- 'userAgent': this.userAgents['chrome'],
- 'has': {
- 'CORS': false,
- 'fetchCurrencies': true,
- 'fetchOHLCV': false,
- 'fetchTrades': false,
- 'fetchOpenOrders': true,
- 'fetchDepositAddress': true,
- 'fetchTransactions': true,
- 'fetchMyTrades': true,
- 'createDepositAddress': false,
- 'withdraw': true,
- },
- 'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27765983-fd8595da-5ec9-11e7-82e3-adb3ab8c2612.jpg',
- 'api': {
- 'public': 'https://anxpro.com/api/2',
- 'private': 'https://anxpro.com/api/2',
- 'v3public': 'https://anxpro.com/api/3',
- 'v3private': 'https://anxpro.com/api/3',
- },
- 'www': 'https://anxpro.com',
- 'doc': [
- 'https://anxv2.docs.apiary.io',
- 'https://anxv3.docs.apiary.io',
- 'https://anxpro.com/pages/api',
- ],
- },
- 'api': {
- 'v3public': {
- 'get': [
- 'currencyStatic',
- ],
- },
- 'v3private': {
- 'post': [
- 'register/register',
- 'register/verifyRegistration',
- 'register/resendVerification',
- 'register/autoRegister',
- 'account',
- 'subaccount/new',
- 'transaction/list',
- 'order/list',
- 'trade/list',
- 'send',
- 'receive',
- 'receive/create',
- 'batch/new',
- 'batch/add',
- 'batch/list',
- 'batch/info',
- 'batch/closeForSend',
- 'order/new',
- 'order/info',
- 'order/cancel',
- 'retail/quote',
- 'retail/trade',
- 'validateAddress',
- 'address/check',
- 'alert/create',
- 'alert/delete',
- 'alert/list',
- 'kyc/personal',
- 'kyc/document',
- 'kyc/status',
- 'kyc/verifyCode',
- 'news/list',
- 'press/list',
- 'announcements/list',
- 'apiDoc/list',
- ],
- },
- 'public': {
- 'get': [
- '{currency_pair}/money/ticker',
- '{currency_pair}/money/depth/full',
- '{currency_pair}/money/trade/fetch', // disabled by ANXPro
- ],
- },
- 'private': {
- 'post': [
- '{currency_pair}/money/order/add',
- '{currency_pair}/money/order/cancel',
- '{currency_pair}/money/order/quote',
- '{currency_pair}/money/order/result',
- '{currency_pair}/money/orders',
- 'money/{currency}/address',
- 'money/{currency}/send_simple',
- 'money/info',
- 'money/trade/list',
- 'money/wallet/history',
- ],
- },
- },
- 'httpExceptions': {
- '403': AuthenticationError,
- },
- 'exceptions': {
- 'exact': {
- // v2
- 'Insufficient Funds': InsufficientFunds,
- 'Trade value too small': InvalidOrder,
- 'The currency pair is not supported': BadRequest,
- 'Order amount is too low': InvalidOrder,
- 'Order amount is too high': InvalidOrder,
- 'order rate is too low': InvalidOrder,
- 'order rate is too high': InvalidOrder,
- 'Too many open orders': InvalidOrder,
- 'Unexpected error': ExchangeError,
- 'Order Engine is offline': ExchangeNotAvailable,
- 'No executed order with that identifer found': OrderNotFound,
- 'Unknown server error, please contact support.': ExchangeError,
- 'Not available': ExchangeNotAvailable, // { "status": "Not available" }
- },
- },
- 'fees': {
- 'trading': {
- 'tierBased': false,
- 'percentage': true,
- 'maker': 0.1 / 100,
- 'taker': 0.2 / 100,
- },
- },
- 'options': {
- 'fetchMyTradesMethod': 'private_post_money_trade_list', // or 'v3private_post_trade_list'
- },
- });
- }
-
- async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
- // todo: migrate this to fetchLedger
- await this.loadMarkets ();
- const request = {};
- if (since !== undefined) {
- request['from'] = since;
- }
- if (limit !== undefined) {
- request['max'] = limit;
- }
- const currency = (code === undefined) ? undefined : this.currency (code);
- if (currency !== undefined) {
- request['ccy'] = currency['id'];
- }
- const response = await this.v3privatePostTransactionList (this.extend (request, params));
- //
- // {
- // transactions: [
- // {
- // transactionClass: 'COIN',
- // uuid: '7896857b-2ed6-4c62-ba4c-619837438d9c',
- // userUuid: '82027ee9-cb59-4f29-80d6-f7e793f39ad4',
- // amount: -17865.72689976,
- // fee: 1,
- // balanceBefore: 17865.72689976,
- // balanceAfter: 17865.72689976,
- // ccy: 'XRP',
- // transactionState: 'PROCESSED',
- // transactionType: 'WITHDRAWAL',
- // received: '1551357946000',
- // processed: '1551357946000',
- // timestampMillis: '1557441435932',
- // displayTitle: 'Coin Withdrawal',
- // displayDescription: 'Withdraw to: rw2ciyaNshpHe7bCHo4bRWq6pqqynnWKQg?dt=3750180345',
- // coinAddress: 'rw2ciyaNshpHe7bCHo4bRWq6pqqynnWKQg?dt=3750180345',
- // coinTransactionId: '68444611753E9D8F5C33DCBBF43F01391070F79CAFCF7625397D1CEFA519064A',
- // subAccount: [
- // Object
- // ]
- // },
- // {
- // transactionClass: 'FILL',
- // uuid: 'a5ae54de-c14a-4ef8-842d-56000c9dc7ab',
- // userUuid: '82027ee9-cb59-4f29-80d6-f7e793f39ad4',
- // amount: 0.09006364,
- // fee: 0.00018013,
- // balanceBefore: 0.3190001,
- // balanceAfter: 0.40888361,
- // ccy: 'BTC',
- // transactionState: 'PROCESSED',
- // transactionType: 'FILL_CREDIT',
- // received: '1551357057000',
- // processed: '1551357057000',
- // timestampMillis: '1557441435956',
- // displayTitle: 'Order Fill',
- // displayDescription: 'Buy BTC @ 3008.53930 EUR/BTC'
- // }
- // ],
- // count: ...,
- // timestamp: '1557441435971',
- // resultCode: 'OK'
- // }
- //
- const transactions = this.safeValue (response, 'transactions', []);
- const grouped = this.groupBy (transactions, 'transactionType', []);
- const depositsAndWithdrawals = this.arrayConcat (this.safeValue (grouped, 'DEPOSIT', []), this.safeValue (grouped, 'WITHDRAWAL', []));
- return this.parseTransactions (depositsAndWithdrawals, currency, since, limit);
- }
-
- parseTransaction (transaction, currency = undefined) {
- //
- // withdrawal
- //
- // {
- // transactionClass: 'COIN',
- // uuid: 'bff91938-4dad-4c48-9db6-468324ce96c1',
- // userUuid: '82027ee9-cb59-4f29-80d6-f7e793f39ad4',
- // amount: -0.40888361,
- // fee: 0.002,
- // balanceBefore: 0.40888361,
- // balanceAfter: 0.40888361,
- // ccy: 'BTC',
- // transactionState: 'PROCESSED',
- // transactionType: 'WITHDRAWAL',
- // received: '1551357156000',
- // processed: '1551357156000',
- // timestampMillis: '1557441846213',
- // displayTitle: 'Coin Withdrawal',
- // displayDescription: 'Withdraw to: 1AHnhqbvbYx3rnZx8uC7NbFZaTe4tafFHX',
- // coinAddress: '1AHnhqbvbYx3rnZx8uC7NbFZaTe4tafFHX',
- // coinTransactionId:
- // 'ab80abcb62bf6261ebc827c73dd59a4ce15d740b6ba734af6542f43b6485b923',
- // subAccount: {
- // uuid: '652e1add-0d0b-462c-a03c-d6197c825c1a',
- // name: 'DEFAULT'
- // }
- // }
- //
- // deposit
- //
- // {
- // "transactionClass": "COIN",
- // "uuid": "eb65576f-c1a8-423c-8e2f-fa50109b2eab",
- // "userUuid": "82027ee9-cb59-4f29-80d6-f7e793f39ad4",
- // "amount": 3.99287184,
- // "fee": 0,
- // "balanceBefore": 8.39666034,
- // "balanceAfter": 12.38953218,
- // "ccy": "ETH",
- // "transactionState": "PROCESSED",
- // "transactionType": "DEPOSIT",
- // "received": "1529420056000",
- // "processed": "1529420766000",
- // "timestampMillis": "1557442743854",
- // "displayTitle": "Coin Deposit",
- // "displayDescription": "Deposit to: 0xf123aa44fadea913a7da99cc2ee202db684ce0e3",
- // "coinTransactionId": "0x33a3e5ea7c034dc5324a88aa313962df0a5d571ab4bcc3cb00b876b1bdfc54f7",
- // "coinConfirmations": 51,
- // "coinConfirmationsRequired": 45,
- // "subAccount": {"uuid": "aba1de05-c7c6-49d7-84ab-a6aca0e827b6", "name": "DEFAULT"}
- // }
- //
- const timestamp = this.safeInteger (transaction, 'received');
- const updated = this.safeInteger (transaction, 'processed');
- const transactionType = this.safeString (transaction, 'transactionType');
- let type = undefined;
- let amount = this.safeFloat (transaction, 'amount');
- let address = this.safeString (transaction, 'coinAddress');
- let tag = undefined;
- if (transactionType === 'WITHDRAWAL') {
- type = 'withdrawal';
- amount = -amount;
- if (address) {
- // xrp: "coinAddress": "rw2ciyaNshpHe7bCHo4bRWq6pqqynnWKQg?dt=3750180345",
- if (address.indexOf ('?dt=') >= 0) {
- const parts = address.split ('?dt=');
- address = parts[0];
- tag = parts[1];
- }
- }
- } else if (transactionType === 'DEPOSIT') {
- if (!address) {
- const displayDescription = this.safeString (transaction, 'displayDescription');
- const addressText = displayDescription.replace ('Deposit to: ', '');
- if (addressText.length > 0) {
- // eth: "displayDescription": "Deposit to: 0xf123aa44fadea913a7da99cc2ee202db684ce0e3",
- // xrp: "displayDescription": "Deposit to: rUjxty1WWLwX1evhKf3C2XNZDMcXEZ9ToJ?dt=504562345",
- if (addressText.indexOf ('?dt=') >= 0) {
- const parts = addressText.split ('?dt=');
- address = parts[0];
- tag = parts[1];
- } else {
- address = addressText;
- }
- }
- }
- type = 'deposit';
- }
- const currencyId = this.safeString (transaction, 'ccy');
- const code = this.safeCurrencyCode (currencyId);
- const transactionState = this.safeString (transaction, 'transactionState');
- const status = this.parseTransactionStatus (transactionState);
- const feeCost = this.safeFloat (transaction, 'fee');
- const netAmount = amount - feeCost;
- return {
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'id': this.safeString (transaction, 'uuid'),
- 'currency': code,
- 'amount': netAmount,
- 'address': address,
- 'tag': tag,
- 'status': status,
- 'type': type,
- 'updated': updated,
- 'txid': this.safeString (transaction, 'coinTransactionId'),
- 'fee': {
- 'cost': feeCost,
- 'currency': code,
- },
- 'info': transaction,
- };
- }
-
- parseTransactionStatus (status) {
- const statuses = {
- 'PROCESSED': 'ok',
- 'REVERSED': 'canceled',
- 'CANCELLED_INSUFFICIENT_FUNDS': 'canceled',
- 'CANCELLED_LIMIT_BREACH': 'canceled',
- };
- return this.safeString (statuses, status, status);
- }
-
- async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- //
- // v2
- //
- // {
- // result: 'success',
- // data: [
- // {
- // tradeId: 'c2ed821d-717a-4b7e-beb0-a9ba60e8f5a0',
- // orderId: '5a65ae21-c7a8-4009-b3af-306c2ad21a02',
- // timestamp: '1551357057000',
- // tradedCurrencyFillAmount: '0.09006364',
- // settlementCurrencyFillAmount: '270.96',
- // settlementCurrencyFillAmountUnrounded: '270.96000000',
- // price: '3008.53930',
- // ccyPair: 'BTCEUR',
- // side: 'BUY' // missing in v3
- // },
- // {
- // tradeId: 'fc0d3a9d-8b0b-4dff-b2e9-edd160785210',
- // orderId: '8161ae6e-251a-4eed-a56f-d3d6555730c1',
- // timestamp: '1551357033000',
- // tradedCurrencyFillAmount: '0.06521746',
- // settlementCurrencyFillAmount: '224.09',
- // settlementCurrencyFillAmountUnrounded: '224.09000000',
- // price: '3436.04305',
- // ccyPair: 'BTCUSD',
- // side: 'BUY' // missing in v3
- // },
- // ]
- // }
- //
- // v3
- //
- // {
- // trades: [
- // {
- // tradeId: 'c2ed821d-717a-4b7e-beb0-a9ba60e8f5a0',
- // orderId: '5a65ae21-c7a8-4009-b3af-306c2ad21a02',
- // timestamp: '1551357057000',
- // tradedCurrencyFillAmount: '0.09006364',
- // settlementCurrencyFillAmount: '270.96',
- // settlementCurrencyFillAmountUnrounded: '270.96000000',
- // price: '3008.53930',
- // ccyPair: 'BTCEUR'
- // },
- // {
- // tradeId: 'fc0d3a9d-8b0b-4dff-b2e9-edd160785210',
- // orderId: '8161ae6e-251a-4eed-a56f-d3d6555730c1',
- // timestamp: '1551357033000',
- // tradedCurrencyFillAmount: '0.06521746',
- // settlementCurrencyFillAmount: '224.09',
- // settlementCurrencyFillAmountUnrounded: '224.09000000',
- // price: '3436.04305',
- // ccyPair: 'BTCUSD'
- // },
- // ],
- // count: 3,
- // timestamp: '1557438456732',
- // resultCode: 'OK'
- // }
- //
- const request = {};
- if (limit !== undefined) {
- request['max'] = limit;
- }
- const method = this.safeString (this.options, 'fetchMyTradesMethod', 'private_post_money_trade_list');
- const response = await this[method] (this.extend (request, params));
- const trades = this.safeValue2 (response, 'trades', 'data', []);
- const market = (symbol === undefined) ? undefined : this.market (symbol);
- return this.parseTrades (trades, market, since, limit);
- }
-
- parseTrade (trade, market = undefined) {
- //
- // v2
- //
- // {
- // tradeId: 'fc0d3a9d-8b0b-4dff-b2e9-edd160785210',
- // orderId: '8161ae6e-251a-4eed-a56f-d3d6555730c1',
- // timestamp: '1551357033000',
- // tradedCurrencyFillAmount: '0.06521746',
- // settlementCurrencyFillAmount: '224.09',
- // settlementCurrencyFillAmountUnrounded: '224.09000000',
- // price: '3436.04305',
- // ccyPair: 'BTCUSD',
- // side: 'BUY', // missing in v3
- // }
- //
- // v3
- //
- // {
- // tradeId: 'fc0d3a9d-8b0b-4dff-b2e9-edd160785210',
- // orderId: '8161ae6e-251a-4eed-a56f-d3d6555730c1',
- // timestamp: '1551357033000',
- // tradedCurrencyFillAmount: '0.06521746',
- // settlementCurrencyFillAmount: '224.09',
- // settlementCurrencyFillAmountUnrounded: '224.09000000',
- // price: '3436.04305',
- // ccyPair: 'BTCUSD'
- // }
- //
- const id = this.safeString (trade, 'tradeId');
- const orderId = this.safeString (trade, 'orderId');
- const timestamp = this.safeInteger (trade, 'timestamp');
- const price = this.safeFloat (trade, 'price');
- const amount = this.safeFloat (trade, 'tradedCurrencyFillAmount');
- const cost = this.safeFloat (trade, 'settlementCurrencyFillAmount');
- const side = this.safeStringLower (trade, 'side');
- let symbol = undefined;
- const marketId = this.safeString (trade, 'ccyPair');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
- return {
- 'id': id,
- 'order': orderId,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'symbol': symbol,
- 'type': undefined,
- 'side': side,
- 'price': price,
- 'amount': amount,
- 'cost': cost,
- 'fee': undefined,
- 'info': trade,
- 'takerOrMaker': undefined,
- };
- }
-
- async fetchCurrencies (params = {}) {
- const response = await this.v3publicGetCurrencyStatic (params);
- //
- // {
- // "currencyStatic": {
- // "currencies": {
- // "HKD": {
- // "decimals": 2,
- // "minOrderSize": 1.00000000,
- // "maxOrderSize": 10000000000.00000000,
- // "displayDenominator": 1,
- // "summaryDecimals": 0,
- // "displayUnit": "HKD",
- // "symbol": "$",
- // "type": "FIAT",
- // "engineSettings": {
- // "depositsEnabled": false,
- // "withdrawalsEnabled": true,
- // "displayEnabled": true,
- // "mobileAccessEnabled": true
- // },
- // "minOrderValue": 1.00000000,
- // "maxOrderValue": 10000000000.00000000,
- // "maxMarketOrderValue": 36000.00000000,
- // "maxMarketOrderSize": 36000.00000000,
- // "assetDivisibility": 0
- // },
- // "ETH": {
- // "decimals": 8,
- // "minOrderSize": 0.00010000,
- // "maxOrderSize": 1000000000.00000000,
- // "type": "CRYPTO",
- // "confirmationThresholds": [
- // { "confosRequired": 30, "threshold": 0.50000000 },
- // { "confosRequired": 45, "threshold": 10.00000000 },
- // { "confosRequired": 70 }
- // ],
- // "networkFee": 0.00500000,
- // "engineSettings": {
- // "depositsEnabled": true,
- // "withdrawalsEnabled": true,
- // "displayEnabled": true,
- // "mobileAccessEnabled": true
- // },
- // "minOrderValue": 0.00010000,
- // "maxOrderValue": 10000000000.00000000,
- // "maxMarketOrderValue": 10000000000.00000000,
- // "maxMarketOrderSize": 1000000000.00000000,
- // "digitalCurrencyType": "ETHEREUM",
- // "assetDivisibility": 0,
- // "assetIcon": "/images/currencies/crypto/ETH.svg"
- // },
- // },
- // "currencyPairs": {
- // "ETHUSD": {
- // "priceDecimals": 5,
- // "engineSettings": {
- // "tradingEnabled": true,
- // "displayEnabled": true,
- // "cancelOnly": true,
- // "verifyRequired": false,
- // "restrictedBuy": false,
- // "restrictedSell": false
- // },
- // "minOrderRate": 10.00000000,
- // "maxOrderRate": 10000.00000000,
- // "displayPriceDecimals": 5,
- // "tradedCcy": "ETH",
- // "settlementCcy": "USD",
- // "preferredMarket": "ANX",
- // "chartEnabled": true,
- // "simpleTradeEnabled": false
- // },
- // },
- // },
- // "timestamp": "1549840691039",
- // "resultCode": "OK"
- // }
- //
- const currencyStatic = this.safeValue (response, 'currencyStatic', {});
- const currencies = this.safeValue (currencyStatic, 'currencies', {});
- const result = {};
- const ids = Object.keys (currencies);
- for (let i = 0; i < ids.length; i++) {
- const id = ids[i];
- const currency = currencies[id];
- const code = this.safeCurrencyCode (id);
- const engineSettings = this.safeValue (currency, 'engineSettings');
- const depositsEnabled = this.safeValue (engineSettings, 'depositsEnabled');
- const withdrawalsEnabled = this.safeValue (engineSettings, 'withdrawalsEnabled');
- const displayEnabled = this.safeValue (engineSettings, 'displayEnabled');
- const active = depositsEnabled && withdrawalsEnabled && displayEnabled;
- const precision = this.safeInteger (currency, 'decimals');
- const fee = this.safeFloat (currency, 'networkFee');
- const type = this.safeStringLower (currency, 'type');
- result[code] = {
- 'id': id,
- 'code': code,
- 'info': currency,
- 'name': code,
- 'type': type,
- 'active': active,
- 'precision': precision,
- 'fee': fee,
- 'limits': {
- 'amount': {
- 'min': this.safeFloat (currency, 'minOrderSize'),
- 'max': this.safeFloat (currency, 'maxOrderSize'),
- },
- 'price': {
- 'min': undefined,
- 'max': undefined,
- },
- 'cost': {
- 'min': this.safeFloat (currency, 'minOrderValue'),
- 'max': this.safeFloat (currency, 'maxOrderValue'),
- },
- 'withdraw': {
- 'min': undefined,
- 'max': undefined,
- },
- },
- };
- }
- return result;
- }
-
- async fetchMarkets (params = {}) {
- const response = await this.v3publicGetCurrencyStatic (params);
- //
- // {
- // "currencyStatic": {
- // "currencies": {
- // "HKD": {
- // "decimals": 2,
- // "minOrderSize": 1.00000000,
- // "maxOrderSize": 10000000000.00000000,
- // "displayDenominator": 1,
- // "summaryDecimals": 0,
- // "displayUnit": "HKD",
- // "symbol": "$",
- // "type": "FIAT",
- // "engineSettings": {
- // "depositsEnabled": false,
- // "withdrawalsEnabled": true,
- // "displayEnabled": true,
- // "mobileAccessEnabled": true
- // },
- // "minOrderValue": 1.00000000,
- // "maxOrderValue": 10000000000.00000000,
- // "maxMarketOrderValue": 36000.00000000,
- // "maxMarketOrderSize": 36000.00000000,
- // "assetDivisibility": 0
- // },
- // "ETH": {
- // "decimals": 8,
- // "minOrderSize": 0.00010000,
- // "maxOrderSize": 1000000000.00000000,
- // "type": "CRYPTO",
- // "confirmationThresholds": [
- // { "confosRequired": 30, "threshold": 0.50000000 },
- // { "confosRequired": 45, "threshold": 10.00000000 },
- // { "confosRequired": 70 }
- // ],
- // "networkFee": 0.00500000,
- // "engineSettings": {
- // "depositsEnabled": true,
- // "withdrawalsEnabled": true,
- // "displayEnabled": true,
- // "mobileAccessEnabled": true
- // },
- // "minOrderValue": 0.00010000,
- // "maxOrderValue": 10000000000.00000000,
- // "maxMarketOrderValue": 10000000000.00000000,
- // "maxMarketOrderSize": 1000000000.00000000,
- // "digitalCurrencyType": "ETHEREUM",
- // "assetDivisibility": 0,
- // "assetIcon": "/images/currencies/crypto/ETH.svg"
- // },
- // },
- // "currencyPairs": {
- // "ETHUSD": {
- // "priceDecimals": 5,
- // "engineSettings": {
- // "tradingEnabled": true,
- // "displayEnabled": true,
- // "cancelOnly": true,
- // "verifyRequired": false,
- // "restrictedBuy": false,
- // "restrictedSell": false
- // },
- // "minOrderRate": 10.00000000,
- // "maxOrderRate": 10000.00000000,
- // "displayPriceDecimals": 5,
- // "tradedCcy": "ETH",
- // "settlementCcy": "USD",
- // "preferredMarket": "ANX",
- // "chartEnabled": true,
- // "simpleTradeEnabled": false
- // },
- // },
- // },
- // "timestamp": "1549840691039",
- // "resultCode": "OK"
- // }
- //
- const currencyStatic = this.safeValue (response, 'currencyStatic', {});
- const currencies = this.safeValue (currencyStatic, 'currencies', {});
- const currencyPairs = this.safeValue (currencyStatic, 'currencyPairs', {});
- const result = [];
- const ids = Object.keys (currencyPairs);
- for (let i = 0; i < ids.length; i++) {
- const id = ids[i];
- const market = currencyPairs[id];
- //
- // "ETHUSD": {
- // "priceDecimals": 5,
- // "engineSettings": {
- // "tradingEnabled": true,
- // "displayEnabled": true,
- // "cancelOnly": true,
- // "verifyRequired": false,
- // "restrictedBuy": false,
- // "restrictedSell": false
- // },
- // "minOrderRate": 10.00000000,
- // "maxOrderRate": 10000.00000000,
- // "displayPriceDecimals": 5,
- // "tradedCcy": "ETH",
- // "settlementCcy": "USD",
- // "preferredMarket": "ANX",
- // "chartEnabled": true,
- // "simpleTradeEnabled": false
- // },
- //
- const baseId = this.safeString (market, 'tradedCcy');
- const quoteId = this.safeString (market, 'settlementCcy');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- const symbol = base + '/' + quote;
- const baseCurrency = this.safeValue (currencies, baseId, {});
- const quoteCurrency = this.safeValue (currencies, quoteId, {});
- const precision = {
- 'price': this.safeInteger (market, 'priceDecimals'),
- 'amount': this.safeInteger (baseCurrency, 'decimals'),
- };
- const engineSettings = this.safeValue (market, 'engineSettings');
- const displayEnabled = this.safeValue (engineSettings, 'displayEnabled');
- const tradingEnabled = this.safeValue (engineSettings, 'tradingEnabled');
- const active = displayEnabled && tradingEnabled;
- result.push ({
- 'id': id,
- 'symbol': symbol,
- 'base': base,
- 'quote': quote,
- 'baseId': baseId,
- 'quoteId': quoteId,
- 'precision': precision,
- 'active': active,
- 'limits': {
- 'price': {
- 'min': this.safeFloat (market, 'minOrderRate'),
- 'max': this.safeFloat (market, 'maxOrderRate'),
- },
- 'amount': {
- 'min': this.safeFloat (baseCurrency, 'minOrderSize'),
- 'max': this.safeFloat (baseCurrency, 'maxOrderSize'),
- },
- 'cost': {
- 'min': this.safeFloat (quoteCurrency, 'minOrderValue'),
- 'max': this.safeFloat (quoteCurrency, 'maxOrderValue'),
- },
- },
- 'info': market,
- });
- }
- return result;
- }
-
- async fetchBalance (params = {}) {
- await this.loadMarkets ();
- const response = await this.privatePostMoneyInfo (params);
- const balance = this.safeValue (response, 'data', {});
- const wallets = this.safeValue (balance, 'Wallets', {});
- const currencyIds = Object.keys (wallets);
- const result = { 'info': balance };
- for (let c = 0; c < currencyIds.length; c++) {
- const currencyId = currencyIds[c];
- const code = this.safeCurrencyCode (currencyId);
- const account = this.account ();
- const wallet = this.safeValue (wallets, currencyId);
- account['free'] = this.safeFloat (wallet['Available_Balance'], 'value');
- account['total'] = this.safeFloat (wallet['Balance'], 'value');
- result[code] = account;
- }
- return this.parseBalance (result);
- }
-
- async fetchOrderBook (symbol, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'currency_pair': this.marketId (symbol),
- };
- const response = await this.publicGetCurrencyPairMoneyDepthFull (this.extend (request, params));
- const orderbook = this.safeValue (response, 'data', {});
- const timestamp = this.safeIntegerProduct (orderbook, 'dataUpdateTime', 0.001);
- return this.parseOrderBook (orderbook, timestamp, 'bids', 'asks', 'price', 'amount');
- }
-
- async fetchTicker (symbol, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'currency_pair': this.marketId (symbol),
- };
- const response = await this.publicGetCurrencyPairMoneyTicker (this.extend (request, params));
- const ticker = this.safeValue (response, 'data', {});
- const timestamp = this.safeIntegerProduct (ticker, 'dataUpdateTime', 0.001);
- const bid = this.safeFloat (ticker['buy'], 'value');
- const ask = this.safeFloat (ticker['sell'], 'value');
- const baseVolume = this.safeFloat (ticker['vol'], 'value');
- const last = this.safeFloat (ticker['last'], 'value');
- return {
- 'symbol': symbol,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'high': this.safeFloat (ticker['high'], 'value'),
- 'low': this.safeFloat (ticker['low'], 'value'),
- 'bid': bid,
- 'bidVolume': undefined,
- 'ask': ask,
- 'askVolume': undefined,
- 'vwap': undefined,
- 'open': undefined,
- 'close': last,
- 'last': last,
- 'previousClose': undefined,
- 'change': undefined,
- 'percentage': undefined,
- 'average': this.safeFloat (ticker['avg'], 'value'),
- 'baseVolume': baseVolume,
- 'quoteVolume': undefined,
- 'info': ticker,
- };
- }
-
- async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
- throw new NotSupported (this.id + ' switched off the trades endpoint, see their docs at https://docs.anxv2.apiary.io');
- }
-
- async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {};
- if (limit !== undefined) {
- request['max'] = limit;
- }
- const response = await this.v3privatePostOrderList (this.extend (request, params));
- const orders = this.safeValue (response, 'orders', []);
- const market = (symbol === undefined) ? undefined : this.market (symbol);
- return this.parseOrders (orders, market, since, limit);
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'currency_pair': market['id'],
- };
- // ANXPro will return all symbol pairs regardless of what is specified in request
- const response = await this.privatePostCurrencyPairMoneyOrders (this.extend (request, params));
- //
- // {
- // "result": "success",
- // "data": [
- // {
- // "oid": "e74305c7-c424-4fbc-a8a2-b41d8329deb0",
- // "currency": "HKD",
- // "item": "BTC",
- // "type": "offer",
- // "amount": {
- // "currency": "BTC",
- // "display": "10.00000000 BTC",
- // "display_short": "10.00 BTC",
- // "value": "10.00000000",
- // "value_int": "1000000000"
- // },
- // "effective_amount": {
- // "currency": "BTC",
- // "display": "10.00000000 BTC",
- // "display_short": "10.00 BTC",
- // "value": "10.00000000",
- // "value_int": "1000000000"
- // },
- // "price": {
- // "currency": "HKD",
- // "display": "412.34567 HKD",
- // "display_short": "412.35 HKD",
- // "value": "412.34567",
- // "value_int": "41234567"
- // },
- // "status": "open",
- // "date": 1393411075000,
- // "priority": 1393411075000000,
- // "actions": []
- // },
- // ...
- // ]
- // }
- //
- return this.parseOrders (this.safeValue (response, 'data', {}), market, since, limit);
- }
-
- parseOrder (order, market = undefined) {
- if ('orderId' in order) {
- return this.parseOrderV3 (order, market);
- } else {
- return this.parseOrderV2 (order, market);
- }
- }
-
- parseOrderStatus (status) {
- const statuses = {
- 'ACTIVE': 'open',
- 'FULL_FILL': 'closed',
- 'CANCEL': 'canceled',
- 'USER_CANCEL_PARTIAL': 'canceled',
- 'PARTIAL_FILL': 'canceled',
- };
- return this.safeString (statuses, status, status);
- }
-
- parseOrderV3 (order, market = undefined) {
- //
- // v3
- //
- // {
- // orderType: 'LIMIT',
- // tradedCurrency: 'XRP',
- // settlementCurrency: 'BTC',
- // tradedCurrencyAmount: '400.00000000',
- // buyTradedCurrency: true,
- // limitPriceInSettlementCurrency: '0.00007129',
- // timestamp: '1522547850000',
- // orderId: '62a8be4d-73c6-4469-90cd-28b4726effe0',
- // tradedCurrencyAmountOutstanding: '0.00000000',
- // orderStatus: 'FULL_FILL',
- // executedAverageRate: '0.00007127',
- // trades: [
- // {
- // tradeId: 'fe16b796-df57-41a2-b6d9-3489f189749e',
- // orderId: '62a8be4d-73c6-4469-90cd-28b4726effe0',
- // timestamp: '1522547850000',
- // tradedCurrencyFillAmount: '107.91298639',
- // settlementCurrencyFillAmount: '0.00768772',
- // settlementCurrencyFillAmountUnrounded: '0.00768772',
- // price: '0.00007124',
- // ccyPair: 'XRPBTC'
- // },
- // {
- // tradeId: 'e2962f67-c094-4243-8b88-0cdc70a1b1c7',
- // orderId: '62a8be4d-73c6-4469-90cd-28b4726effe0',
- // timestamp: '1522547851000',
- // tradedCurrencyFillAmount: '292.08701361',
- // settlementCurrencyFillAmount: '0.02082288',
- // settlementCurrencyFillAmountUnrounded: '0.02082288',
- // price: '0.00007129',
- // ccyPair: 'XRPBTC'
- // }
- // ]
- // }
- //
- const status = this.parseOrderStatus (this.safeString (order, 'orderStatus'));
- const base = this.safeCurrencyCode (this.safeString (order, 'tradedCurrency'));
- const quote = this.safeCurrencyCode (this.safeString (order, 'settlementCurrency'));
- const symbol = base + '/' + quote;
- const buyTradedCurrency = this.safeString (order, 'buyTradedCurrency');
- const side = (buyTradedCurrency === 'true') ? 'buy' : 'sell';
- const timestamp = this.safeInteger (order, 'timestamp');
- let lastTradeTimestamp = undefined;
- const trades = [];
- let filled = 0;
- const type = this.safeStringLower (order, 'orderType');
- for (let i = 0; i < order['trades'].length; i++) {
- const trade = order['trades'][i];
- const tradeTimestamp = this.safeInteger (trade, 'timestamp');
- if (!lastTradeTimestamp || lastTradeTimestamp < tradeTimestamp) {
- lastTradeTimestamp = tradeTimestamp;
- }
- const parsedTrade = this.extend (this.parseTrade (trade), { 'side': side, 'type': type });
- trades.push (parsedTrade);
- filled = this.sum (filled, parsedTrade['amount']);
- }
- const price = this.safeFloat (order, 'limitPriceInSettlementCurrency');
- const executedAverageRate = this.safeFloat (order, 'executedAverageRate');
- const remaining = (type === 'market') ? 0 : this.safeFloat (order, 'tradedCurrencyAmountOutstanding');
- let amount = this.safeFloat (order, 'tradedCurrencyAmount');
- if (!amount) {
- const settlementCurrencyAmount = this.safeFloat (order, 'settlementCurrencyAmount');
- amount = settlementCurrencyAmount / executedAverageRate;
- }
- const cost = executedAverageRate * filled;
- return {
- 'id': this.safeString (order, 'orderId'),
- 'clientOrderId': undefined,
- 'symbol': symbol,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'lastTradeTimestamp': lastTradeTimestamp,
- 'type': type,
- 'side': side,
- 'price': price,
- 'cost': cost,
- 'amount': amount,
- 'remaining': remaining,
- 'filled': filled,
- 'status': status,
- 'fee': undefined,
- 'trades': trades,
- 'info': order,
- 'average': undefined,
- };
- }
-
- parseOrderV2 (order, market = undefined) {
- //
- // v2
- //
- // {
- // "oid": "e74305c7-c424-4fbc-a8a2-b41d8329deb0",
- // "currency": "HKD",
- // "item": "BTC",
- // "type": "offer", <-- bid/offer
- // "amount": {
- // "currency": "BTC",
- // "display": "10.00000000 BTC",
- // "display_short": "10.00 BTC",
- // "value": "10.00000000",
- // "value_int": "1000000000"
- // },
- // "effective_amount": {
- // "currency": "BTC",
- // "display": "10.00000000 BTC",
- // "display_short": "10.00 BTC",
- // "value": "10.00000000",
- // "value_int": "1000000000"
- // },
- // "price": {
- // "currency": "HKD",
- // "display": "412.34567 HKD",
- // "display_short": "412.35 HKD",
- // "value": "412.34567",
- // "value_int": "41234567"
- // },
- // "status": "open",
- // "date": 1393411075000,
- // "priority": 1393411075000000,
- // "actions": []
- // }
- //
- const id = this.safeString (order, 'oid');
- const status = this.safeString (order, 'status');
- const timestamp = this.safeInteger (order, 'date');
- const baseId = this.safeString (order, 'item');
- const quoteId = this.safeString (order, 'currency');
- const marketId = baseId + '/' + quoteId;
- market = this.safeValue (this.markets_by_id, marketId);
- let symbol = undefined;
- if (typeof market !== 'undefined') {
- symbol = market['symbol'];
- }
- const amount_info = this.safeValue (order, 'amount', {});
- const effective_info = this.safeValue (order, 'effective_amount', {});
- const price_info = this.safeValue (order, 'price', {});
- const remaining = this.safeFloat (effective_info, 'value');
- const amount = this.safeFloat (amount_info, 'volume');
- const price = this.safeFloat (price_info, 'value');
- let filled = undefined;
- let cost = undefined;
- if (typeof amount !== 'undefined') {
- if (typeof remaining !== 'undefined') {
- filled = amount - remaining;
- cost = price * filled;
- }
- }
- const orderType = 'limit';
- let side = this.safeString (order, 'type');
- if (side === 'offer') {
- side = 'sell';
- } else {
- side = 'buy';
- }
- const fee = undefined;
- const trades = undefined; // todo parse trades
- const lastTradeTimestamp = undefined;
- return {
- 'info': order,
- 'id': id,
- 'clientOrderId': undefined,
- 'symbol': symbol,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'lastTradeTimestamp': lastTradeTimestamp,
- 'type': orderType,
- 'side': side,
- 'price': price,
- 'cost': cost,
- 'amount': amount,
- 'remaining': remaining,
- 'filled': filled,
- 'status': status,
- 'fee': fee,
- 'trades': trades,
- 'average': undefined,
- };
- }
-
- async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const amountMultiplier = Math.pow (10, market['precision']['amount']);
- const request = {
- 'currency_pair': market['id'],
- 'amount_int': parseInt (amount * amountMultiplier), // 10^8
- };
- if (type === 'limit') {
- const priceMultiplier = Math.pow (10, market['precision']['price']);
- request['price_int'] = parseInt (price * priceMultiplier); // 10^5 or 10^8
- }
- request['type'] = (side === 'buy') ? 'bid' : 'ask';
- const response = await this.privatePostCurrencyPairMoneyOrderAdd (this.extend (request, params));
- return {
- 'info': response,
- 'id': response['data'],
- };
- }
-
- async cancelOrder (id, symbol = undefined, params = {}) {
- return await this.privatePostCurrencyPairMoneyOrderCancel ({ 'oid': id });
- }
-
- getAmountMultiplier (code) {
- const multipliers = {
- 'BTC': 100000000,
- 'LTC': 100000000,
- 'STR': 100000000,
- 'XRP': 100000000,
- 'DOGE': 100000000,
- };
- const defaultValue = 100;
- return this.safeInteger (multipliers, code, defaultValue);
- }
-
- async withdraw (code, amount, address, tag = undefined, params = {}) {
- this.checkAddress (address);
- await this.loadMarkets ();
- const currency = this.currency (code);
- const multiplier = this.getAmountMultiplier (code);
- const request = {
- 'currency': currency,
- 'amount_int': parseInt (amount * multiplier),
- 'address': address,
- };
- if (tag !== undefined) {
- request['destinationTag'] = tag;
- }
- const response = await this.privatePostMoneyCurrencySendSimple (this.extend (request, params));
- return {
- 'info': response,
- 'id': response['data']['transactionId'],
- };
- }
-
- async fetchDepositAddress (code, params = {}) {
- await this.loadMarkets ();
- const currency = this.currency (code);
- const request = {
- 'currency': currency['id'],
- };
- const response = await this.privatePostMoneyCurrencyAddress (this.extend (request, params));
- const data = this.safeValue (response, 'data', {});
- const address = this.safeString (data, 'addr');
- this.checkAddress (address);
- return {
- 'currency': code,
- 'address': address,
- 'tag': undefined,
- 'info': response,
- };
- }
-
- nonce () {
- return this.milliseconds ();
- }
-
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- const request = this.implodeParams (path, params);
- const query = this.omit (params, this.extractParams (path));
- let url = this.urls['api'][api] + '/' + request;
- if (api === 'public' || api === 'v3public') {
- if (Object.keys (query).length) {
- url += '?' + this.urlencode (query);
- }
- } else {
- this.checkRequiredCredentials ();
- const nonce = this.nonce ();
- let auth = undefined;
- let contentType = undefined;
- if (api === 'v3private') {
- body = this.json (this.extend ({ 'tonce': nonce * 1000 }, query));
- const path = url.replace ('https://anxpro.com/', '');
- auth = path + '\0' + body;
- contentType = 'application/json';
- } else {
- body = this.urlencode (this.extend ({ 'nonce': nonce }, query));
- // eslint-disable-next-line quotes
- auth = request + "\0" + body;
- contentType = 'application/x-www-form-urlencoded';
- }
- const secret = this.base64ToBinary (this.secret);
- const signature = this.hmac (this.encode (auth), secret, 'sha512', 'base64');
- headers = {
- 'Content-Type': contentType,
- 'Rest-Key': this.apiKey,
- 'Rest-Sign': this.decode (signature),
- };
- }
- return { 'url': url, 'method': method, 'body': body, 'headers': headers };
- }
-
- handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
- if (response === undefined || response === '') {
- return;
- }
- const result = this.safeString (response, 'result');
- const code = this.safeString (response, 'resultCode');
- const status = this.safeString (response, 'status');
- if (((result !== undefined) && (result !== 'success')) || ((code !== undefined) && (code !== 'OK')) || (status !== undefined)) {
- const message = this.safeString (response, 'error');
- const feedback = this.id + ' ' + body;
- this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback);
- this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
- this.throwExactlyMatchedException (this.exceptions['exact'], status, feedback);
- this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
- throw new ExchangeError (feedback); // unknown message
- }
- }
-};
-
-},{"./base/Exchange":7,"./base/errors":9}],6:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],4:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -2412,7 +899,7 @@ module.exports = class aofex extends Exchange {
return result;
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// id: 1584950100,
@@ -2482,7 +969,7 @@ module.exports = class aofex extends Exchange {
//
const result = this.safeValue (response, 'result', {});
const data = this.safeValue (result, 'data', []);
- return this.parseOHLCVs (data, market, timeframe, since, limit);
+ return this.parseOHLCVs (data, market, since, limit);
}
async fetchBalance (params = {}) {
@@ -2607,13 +1094,9 @@ module.exports = class aofex extends Exchange {
const percentage = change / open * 100;
const baseVolume = this.safeFloat (ticker, 'amount');
const quoteVolume = this.safeFloat (ticker, 'vol');
- let vwap = undefined;
- if (quoteVolume !== undefined) {
- if (baseVolume !== undefined) {
- if (baseVolume > 0) {
- vwap = parseFloat (this.priceToPrecision (symbol, quoteVolume / baseVolume));
- }
- }
+ let vwap = this.vwap (baseVolume, quoteVolume);
+ if (vwap !== undefined) {
+ vwap = parseFloat (this.priceToPrecision (symbol, vwap));
}
return {
'symbol': symbol,
@@ -2672,23 +1155,10 @@ module.exports = class aofex extends Exchange {
const result = {};
for (let i = 0; i < tickers.length; i++) {
const marketId = this.safeString (tickers[i], 'symbol');
- let market = undefined;
- let symbol = marketId;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
+ const market = this.safeMarket (marketId, undefined, '-');
+ const symbol = market['symbol'];
const data = this.safeValue (tickers[i], 'data', {});
- const ticker = this.parseTicker (data, market);
- ticker['symbol'] = symbol;
- result[symbol] = ticker;
+ result[symbol] = this.parseTicker (data, market);
}
return this.filterByArray (result, 'symbol', symbols);
}
@@ -2892,26 +1362,12 @@ module.exports = class aofex extends Exchange {
const id = this.safeString (order, 'order_sn');
const orderStatus = this.safeString (order, 'status');
const status = this.parseOrderStatus (orderStatus);
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- let base = undefined;
- let quote = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- base = this.safeCurrencyCode (baseId);
- quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ market = this.safeMarket (marketId, market, '-');
+ let timestamp = this.parse8601 (this.safeString (order, 'ctime'));
+ if (timestamp !== undefined) {
+ timestamp -= 28800000; // 8 hours, adjust to UTC
}
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- base = market['base'];
- quote = market['quote'];
- }
- const timestamp = this.parse8601 (this.safeString (order, 'ctime')) - 28800000; // 8 hours, adjust to UTC
const orderType = this.safeString (order, 'type');
const type = (orderType === '2') ? 'limit' : 'market';
const side = this.safeString (order, 'side');
@@ -2975,7 +1431,7 @@ module.exports = class aofex extends Exchange {
}
}
if (feeCost !== undefined) {
- const feeCurrencyCode = (side === 'buy') ? base : quote;
+ const feeCurrencyCode = (side === 'buy') ? market['base'] : market['quote'];
fee = {
'cost': feeCost,
'currency': feeCurrencyCode,
@@ -3011,10 +1467,12 @@ module.exports = class aofex extends Exchange {
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
'status': status,
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -3309,8 +1767,7 @@ module.exports = class aofex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],7:[function(require,module,exports){
-(function (Buffer){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],5:[function(require,module,exports){
"use strict";
// ----------------------------------------------------------------------------
@@ -3343,7 +1800,7 @@ const {
, defaultFetch
} = functions
-const {
+const { // eslint-disable-line object-curly-newline
ExchangeError
, BadSymbol
, InvalidAddress
@@ -3354,26 +1811,10 @@ const {
, ExchangeNotAvailable
, RateLimitExceeded } = require ('./errors')
-const { TRUNCATE, ROUND, DECIMAL_PLACES } = functions.precisionConstants
+const { TRUNCATE, ROUND, DECIMAL_PLACES, NO_PADDING } = functions.precisionConstants
const BN = require ('../static_dependencies/BN/bn')
-// ----------------------------------------------------------------------------
-// web3 / 0x imports
-
-let ethAbi = undefined
- , ethUtil = undefined
-
-try {
- const requireFunction = require;
- ethAbi = requireFunction ('ethereumjs-abi') // eslint-disable-line global-require
- ethUtil = requireFunction ('ethereumjs-util') // eslint-disable-line global-require
- // we prefer bignumber.js over BN.js
- // BN = requireFunction ('bn.js') // eslint-disable-line global-require
-} catch (e) {
- // nothing
-}
-
// ----------------------------------------------------------------------------
module.exports = class Exchange {
@@ -3388,6 +1829,7 @@ module.exports = class Exchange {
'certified': false,
'pro': false,
'has': {
+ 'loadMarkets': true,
'cancelAllOrders': false,
'cancelOrder': true,
'cancelOrders': false,
@@ -3428,6 +1870,7 @@ module.exports = class Exchange {
'fetchWithdrawals': false,
'privateAPI': true,
'publicAPI': true,
+ 'signIn': false,
'withdraw': false,
},
'urls': {
@@ -3511,6 +1954,7 @@ module.exports = class Exchange {
'BCHSV': 'BSV',
},
'precisionMode': DECIMAL_PLACES,
+ 'paddingMode': NO_PADDING,
'limits': {
'amount': { 'min': undefined, 'max': undefined },
'price': { 'min': undefined, 'max': undefined },
@@ -3572,12 +2016,14 @@ module.exports = class Exchange {
this.balance = {}
this.orderbooks = {}
this.tickers = {}
- this.orders = {}
+ this.orders = undefined
this.trades = {}
this.transactions = {}
this.ohlcvs = {}
+ this.myTrades = undefined
this.requiresWeb3 = false
+ this.requiresEddsa = false
this.precision = {}
this.enableLastJsonResponse = true
@@ -3589,7 +2035,9 @@ module.exports = class Exchange {
const unCamelCaseProperties = (obj = this) => {
if (obj !== null) {
- for (const k of Object.getOwnPropertyNames (obj)) {
+ const ownPropertyNames = Object.getOwnPropertyNames (obj)
+ for (let i = 0; i < ownPropertyNames.length; i++) {
+ const k = ownPropertyNames[i]
this[unCamelCase (k)] = this[k]
}
unCamelCaseProperties (Object.getPrototypeOf (obj))
@@ -3597,24 +2045,33 @@ module.exports = class Exchange {
}
unCamelCaseProperties ()
- // merge configs
- const config = deepExtend (this.describe (), userConfig)
-
// merge to this
- for (const [property, value] of Object.entries (config)) {
- this[property] = deepExtend (this[property], value)
+ const configEntries = Object.entries (this.describe ()).concat (Object.entries (userConfig))
+ for (let i = 0; i < configEntries.length; i++) {
+ const [property, value] = configEntries[i]
+ if (value && Object.getPrototypeOf (value) === Object.prototype) {
+ this[property] = deepExtend (this[property], value)
+ } else {
+ this[property] = value
+ }
}
- if (!this.httpAgent) {
- this.httpAgent = defaultFetch.http ? new defaultFetch.http.Agent ({ 'keepAlive': true }) : undefined
+ const agentOptions = {
+ 'keepAlive': true,
}
- if (!this.httpsAgent) {
- this.httpsAgent = defaultFetch.https ? new defaultFetch.https.Agent ({ 'keepAlive': true }) : undefined
+ if (!this.httpAgent && defaultFetch.http && isNode) {
+ this.httpAgent = new defaultFetch.http.Agent (agentOptions)
+ }
+
+ if (!this.httpsAgent && defaultFetch.https && isNode) {
+ this.httpsAgent = new defaultFetch.https.Agent (agentOptions)
}
// generate old metainfo interface
- for (const k in this.has) {
+ const hasKeys = Object.keys (this.has)
+ for (let i = 0; i < hasKeys.length; i++) {
+ const k = hasKeys[i]
this['has' + capitalize (k)] = !!this.has[k] // converts 'emulated' to true
}
@@ -3694,7 +2151,6 @@ module.exports = class Exchange {
const params = { method, headers, body, timeout: this.timeout }
if (this.agent) {
- this.agent.keepAlive = true
params['agent'] = this.agent
} else if (this.httpAgent && url.indexOf ('http://') === 0) {
params['agent'] = this.httpAgent
@@ -3743,46 +2199,31 @@ module.exports = class Exchange {
}
}
- defineRestApi (api, methodName, options = {}) {
-
- for (const type of Object.keys (api)) {
- for (const httpMethod of Object.keys (api[type])) {
-
- let paths = api[type][httpMethod]
- for (let i = 0; i < paths.length; i++) {
- let path = paths[i].trim ()
- let splitPath = path.split (/[^a-zA-Z0-9]/)
-
- let uppercaseMethod = httpMethod.toUpperCase ()
- let lowercaseMethod = httpMethod.toLowerCase ()
- let camelcaseMethod = this.capitalize (lowercaseMethod)
- let camelcaseSuffix = splitPath.map (this.capitalize).join ('')
- let underscoreSuffix = splitPath.map (x => x.trim ().toLowerCase ()).filter (x => x.length > 0).join ('_')
-
- let camelcase = type + camelcaseMethod + this.capitalize (camelcaseSuffix)
- let underscore = type + '_' + lowercaseMethod + '_' + underscoreSuffix
-
- if ('suffixes' in options) {
- if ('camelcase' in options['suffixes']) {
- camelcase += options['suffixes']['camelcase']
- }
- if ('underscore' in options.suffixes) {
- underscore += options['suffixes']['underscore']
- }
- }
-
- if ('underscore_suffix' in options) {
- underscore += options.underscoreSuffix;
- }
- if ('camelcase_suffix' in options) {
- camelcase += options.camelcaseSuffix;
- }
-
- let partial = async params => this[methodName] (path, type, uppercaseMethod, params || {})
-
+ defineRestApi (api, methodName, paths = []) {
+ const keys = Object.keys (api)
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i]
+ const value = api[key]
+ if (Array.isArray (value)) {
+ const uppercaseMethod = key.toUpperCase ()
+ const lowercaseMethod = key.toLowerCase ()
+ const camelcaseMethod = this.capitalize (lowercaseMethod)
+ for (let k = 0; k < value.length; k++) {
+ const path = value[k].trim ()
+ const splitPath = path.split (/[^a-zA-Z0-9]/)
+ const camelcaseSuffix = splitPath.map (this.capitalize).join ('')
+ const underscoreSuffix = splitPath.map ((x) => x.trim ().toLowerCase ()).filter ((x) => x.length > 0).join ('_')
+ const camelcasePrefix = [ paths[0] ].concat (paths.slice (1).map (this.capitalize)).join ('')
+ const underscorePrefix = [ paths[0] ].concat (paths.slice (1).map ((x) => x.trim ()).filter ((x) => x.length > 0)).join ('_')
+ const camelcase = camelcasePrefix + camelcaseMethod + this.capitalize (camelcaseSuffix)
+ const underscore = underscorePrefix + '_' + lowercaseMethod + '_' + underscoreSuffix
+ const typeArgument = (paths.length > 1) ? paths : paths[0]
+ const partial = async (params) => this[methodName] (path, typeArgument, uppercaseMethod, params || {})
this[camelcase] = partial
this[underscore] = partial
}
+ } else {
+ this.defineRestApi (value, methodName, paths.concat ([ key ]))
}
}
}
@@ -3791,6 +2232,10 @@ module.exports = class Exchange {
console.log (... args)
}
+ setHeaders (headers) {
+ return headers;
+ }
+
fetch (url, method = 'GET', headers = undefined, body = undefined) {
if (isNode && this.userAgent) {
@@ -3818,6 +2263,7 @@ module.exports = class Exchange {
}
headers = extend (this.headers, headers)
+ headers = this.setHeaders (headers)
if (this.verbose) {
this.print ("fetch:\n", this.id, method, url, "\nRequest:\n", headers, "\n", body, "\n")
@@ -3880,39 +2326,11 @@ module.exports = class Exchange {
// override me
}
- defaultErrorHandler (code, reason, url, method, headers, body, response) {
- if ((code >= 200) && (code <= 299)) {
- return
- }
- let details = body
+ handleHttpStatusCode (code, reason, url, method, body) {
const codeAsString = code.toString ()
- let ErrorClass = undefined
if (codeAsString in this.httpExceptions) {
- ErrorClass = this.httpExceptions[codeAsString]
- }
- if (response === undefined) {
- const maintenance = body.match (/offline|busy|retry|wait|unavailable|maintain|maintenance|maintenancing/i)
- const ddosProtection = body.match (/cloudflare|incapsula|overload|ddos/i)
- if (maintenance) {
- ErrorClass = ExchangeNotAvailable
- details += ' offline, on maintenance, or unreachable from this location at the moment'
- }
- if (ddosProtection) {
- ErrorClass = DDoSProtection
- }
- }
- if (ErrorClass === ExchangeNotAvailable) {
- details += ' (possible reasons: ' + [
- 'invalid API keys',
- 'bad or old nonce',
- 'exchange is down or offline',
- 'on maintenance',
- 'DDoS protection',
- 'rate-limiting',
- ].join (', ') + ')'
- }
- if (ErrorClass !== undefined) {
- throw new ErrorClass ([ this.id, method, url, code, reason, details ].join (' '))
+ const ErrorClass = this.httpExceptions[codeAsString]
+ throw new ErrorClass ([ this.id, method, url, code, reason, body ].join (' '))
}
}
@@ -3938,11 +2356,11 @@ module.exports = class Exchange {
}
if (this.enableLastHttpResponse) {
- this.last_http_response = responseBody // FIXME: for those classes that haven't switched to handleErrors yet
+ this.last_http_response = responseBody
}
if (this.enableLastJsonResponse) {
- this.last_json_response = json // FIXME: for those classes that haven't switched to handleErrors yet
+ this.last_json_response = json
}
if (this.verbose) {
@@ -3950,7 +2368,7 @@ module.exports = class Exchange {
}
this.handleErrors (response.status, response.statusText, url, method, responseHeaders, responseBody, json, requestHeaders, requestBody)
- this.defaultErrorHandler (response.status, response.statusText, url, method, responseHeaders, responseBody, json)
+ this.handleHttpStatusCode (response.status, response.statusText, url, method, responseBody)
return json || responseBody
})
@@ -3970,16 +2388,16 @@ module.exports = class Exchange {
this.currencies = deepExtend (currencies, this.currencies)
} else {
let baseCurrencies =
- values.filter (market => 'base' in market)
- .map (market => ({
+ values.filter ((market) => 'base' in market)
+ .map ((market) => ({
id: market.baseId || market.base,
numericId: (market.baseNumericId !== undefined) ? market.baseNumericId : undefined,
code: market.base,
precision: market.precision ? (market.precision.base || market.precision.amount) : 8,
}))
let quoteCurrencies =
- values.filter (market => 'quote' in market)
- .map (market => ({
+ values.filter ((market) => 'quote' in market)
+ .map ((market) => ({
id: market.quoteId || market.quote,
numericId: (market.quoteNumericId !== undefined) ? market.quoteNumericId : undefined,
code: market.quote,
@@ -3991,9 +2409,9 @@ module.exports = class Exchange {
this.quoteCurrencies = indexBy (quoteCurrencies, 'code')
const allCurrencies = baseCurrencies.concat (quoteCurrencies)
const groupedCurrencies = groupBy (allCurrencies, 'code')
- const currencies = Object.keys (groupedCurrencies).map (code =>
- groupedCurrencies[code].reduce ((previous, current) =>
- ((previous.precision > current.precision) ? previous : current), groupedCurrencies[code][0]))
+ const currencies = Object.keys (groupedCurrencies).map ((code) =>
+ groupedCurrencies[code].reduce ((previous, current) => // eslint-disable-line implicit-arrow-linebreak
+ ((previous.precision > current.precision) ? previous : current), groupedCurrencies[code][0])) // eslint-disable-line implicit-arrow-linebreak
const sortedCurrencies = sortBy (flatten (currencies), 'code')
this.currencies = deepExtend (indexBy (sortedCurrencies, 'code'), this.currencies)
}
@@ -4049,22 +2467,24 @@ module.exports = class Exchange {
throw new NotSupported (this.id + ' fetchBidsAsks not supported yet')
}
- async fetchOHLCVC (symbol, timeframe = '1m', since = undefined, limits = undefined, params = {}) {
- if (!this.has['fetchTrades'])
+ async fetchOHLCVC (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ if (!this.has['fetchTrades']) {
throw new NotSupported (this.id + ' fetchOHLCV() not supported yet')
+ }
await this.loadMarkets ()
- const trades = await this.fetchTrades (symbol, since, limits, params)
- const ohlcvc = buildOHLCVC (trades, timeframe, since, limits)
+ const trades = await this.fetchTrades (symbol, since, limit, params)
+ const ohlcvc = buildOHLCVC (trades, timeframe, since, limit)
return ohlcvc
}
- async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limits = undefined, params = {}) {
- if (!this.has['fetchTrades'])
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ if (!this.has['fetchTrades']) {
throw new NotSupported (this.id + ' fetchOHLCV() not supported yet')
+ }
await this.loadMarkets ()
- const trades = await this.fetchTrades (symbol, since, limits, params)
- const ohlcvc = buildOHLCVC (trades, timeframe, since, limits)
- return ohlcvc.map (c => c.slice (0, -1))
+ const trades = await this.fetchTrades (symbol, since, limit, params)
+ const ohlcvc = buildOHLCVC (trades, timeframe, since, limit)
+ return ohlcvc.map ((c) => c.slice (0, -1))
}
parseTradingViewOHLCV (ohlcvs, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
@@ -4114,16 +2534,6 @@ module.exports = class Exchange {
throw new NotSupported (this.id + ' fetchTickers not supported yet')
}
- purgeCachedOrders (before) {
- const orders = Object
- .values (this.orders)
- .filter (order =>
- (order.status === 'open') ||
- (order.timestamp >= before))
- this.orders = indexBy (orders, 'id')
- return this.orders
- }
-
fetchOrder (id, symbol = undefined, params = {}) {
throw new NotSupported (this.id + ' fetchOrder not supported yet');
}
@@ -4202,8 +2612,9 @@ module.exports = class Exchange {
}
commonCurrencyCode (currency) {
- if (!this.substituteCommonCurrencyCodes)
+ if (!this.substituteCommonCurrencyCodes) {
return currency
+ }
return this.safeString (this.commonCurrencies, currency, currency)
}
@@ -4229,22 +2640,26 @@ module.exports = class Exchange {
currency (code) {
- if (this.currencies === undefined)
+ if (this.currencies === undefined) {
throw new ExchangeError (this.id + ' currencies not loaded')
+ }
- if ((typeof code === 'string') && (code in this.currencies))
+ if ((typeof code === 'string') && (code in this.currencies)) {
return this.currencies[code]
+ }
throw new ExchangeError (this.id + ' does not have currency code ' + code)
}
market (symbol) {
- if (this.markets === undefined)
+ if (this.markets === undefined) {
throw new ExchangeError (this.id + ' markets not loaded')
+ }
- if ((typeof symbol === 'string') && (symbol in this.markets))
+ if ((typeof symbol === 'string') && (symbol in this.markets)) {
return this.markets[symbol]
+ }
throw new BadSymbol (this.id + ' does not have market symbol ' + symbol)
}
@@ -4255,7 +2670,7 @@ module.exports = class Exchange {
}
marketIds (symbols) {
- return symbols.map (symbol => this.marketId (symbol));
+ return symbols.map ((symbol) => this.marketId (symbol))
}
symbol (symbol) {
@@ -4265,8 +2680,9 @@ module.exports = class Exchange {
url (path, params = {}) {
let result = this.implodeParams (path, params);
const query = this.omit (params, this.extractParams (path))
- if (Object.keys (query).length)
+ if (Object.keys (query).length) {
result += '?' + this.urlencode (query)
+ }
return result
}
@@ -4277,7 +2693,7 @@ module.exports = class Exchange {
}
parseBidsAsks (bidasks, priceKey = 0, amountKey = 1) {
- return Object.values (bidasks || []).map (bidask => this.parseBidAsk (bidask, priceKey, amountKey))
+ return Object.values (bidasks || []).map ((bidask) => this.parseBidAsk (bidask, priceKey, amountKey))
}
async fetchL2OrderBook (symbol, limit = undefined, params = {}) {
@@ -4300,33 +2716,33 @@ module.exports = class Exchange {
parseBalance (balance) {
- const currencies = Object.keys (this.omit (balance, [ 'info', 'free', 'used', 'total' ]));
+ const codes = Object.keys (this.omit (balance, [ 'info', 'free', 'used', 'total' ]));
balance['free'] = {}
balance['used'] = {}
balance['total'] = {}
- for (const currency of currencies) {
-
- if (balance[currency].total === undefined) {
- if (balance[currency].free !== undefined && balance[currency].used !== undefined) {
- balance[currency].total = this.sum (balance[currency].free, balance[currency].used)
+ for (let i = 0; i < codes.length; i++) {
+ const code = codes[i]
+ if (balance[code].total === undefined) {
+ if (balance[code].free !== undefined && balance[code].used !== undefined) {
+ balance[code].total = this.sum (balance[code].free, balance[code].used)
}
}
- if (balance[currency].free === undefined) {
- if (balance[currency].total !== undefined && balance[currency].used !== undefined) {
- balance[currency].free = this.sum (balance[currency].total, -balance[currency].used)
+ if (balance[code].free === undefined) {
+ if (balance[code].total !== undefined && balance[code].used !== undefined) {
+ balance[code].free = this.sum (balance[code].total, -balance[code].used)
}
}
- if (balance[currency].used === undefined) {
- if (balance[currency].total !== undefined && balance[currency].free !== undefined) {
- balance[currency].used = this.sum (balance[currency].total, -balance[currency].free)
+ if (balance[code].used === undefined) {
+ if (balance[code].total !== undefined && balance[code].free !== undefined) {
+ balance[code].used = this.sum (balance[code].total, -balance[code].free)
}
}
- balance.free[currency] = balance[currency].free
- balance.used[currency] = balance[currency].used
- balance.total[currency] = balance[currency].total
+ balance.free[code] = balance[code].free
+ balance.used[code] = balance[code].used
+ balance.total[code] = balance[code].total
}
return balance
@@ -4402,15 +2818,13 @@ module.exports = class Exchange {
// single-pass filter for both symbol and since
if (valueIsDefined || sinceIsDefined) {
- array = Object.values (array).filter ((entry) =>
+ array = array.filter ((entry) =>
((valueIsDefined ? (entry[field] === value) : true) &&
(sinceIsDefined ? (entry[key] >= since) : true)))
}
if (limit !== undefined && limit !== null) {
- array = ((tail && !sinceIsDefined) ?
- Object.values (array).slice (-limit) :
- Object.values (array).slice (0, limit))
+ array = (tail && !sinceIsDefined) ? array.slice (-limit) : array.slice (0, limit)
}
return array
@@ -4484,36 +2898,95 @@ module.exports = class Exchange {
}
parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
- // this code is commented out temporarily to catch for exchange-specific errors
- // if (!this.isArray (orders)) {
- // throw new ExchangeError (this.id + ' parseOrders expected an array in the orders argument, but got ' + typeof orders);
- // }
- let result = Object.values (orders).map (order => this.extend (this.parseOrder (order, market), params))
+ //
+ // the value of orders is either a dict or a list
+ //
+ // dict
+ //
+ // {
+ // 'id1': { ... },
+ // 'id2': { ... },
+ // 'id3': { ... },
+ // ...
+ // }
+ //
+ // list
+ //
+ // [
+ // { 'id': 'id1', ... },
+ // { 'id': 'id2', ... },
+ // { 'id': 'id3', ... },
+ // ...
+ // ]
+ //
+ let result = Array.isArray (orders) ?
+ Object.values (orders).map ((order) => this.extend (this.parseOrder (order, market), params)) :
+ Object.entries (orders).map (([ id, order ]) => this.extend (this.parseOrder (this.extend ({ 'id': id }, order), market), params))
result = sortBy (result, 'timestamp')
const symbol = (market !== undefined) ? market['symbol'] : undefined
return this.filterBySymbolSinceLimit (result, symbol, since, limit)
}
+ safeCurrency (currencyId, currency = undefined) {
+ if ((currencyId === undefined) && (currency !== undefined)) {
+ return currency
+ }
+ if ((this.currencies_by_id !== undefined) && (currencyId in this.currencies_by_id)) {
+ return this.currencies_by_id[currencyId]
+ }
+ return {
+ 'id': currencyId,
+ 'code': (currencyId === undefined) ? currencyId : this.commonCurrencyCode (currencyId.toUpperCase ()),
+ }
+ }
+
safeCurrencyCode (currencyId, currency = undefined) {
- let code = undefined
- if (currencyId !== undefined) {
- if (this.currencies_by_id !== undefined && currencyId in this.currencies_by_id) {
- code = this.currencies_by_id[currencyId]['code']
- } else {
- code = this.commonCurrencyCode (currencyId.toUpperCase ())
+ currency = this.safeCurrency (currencyId, currency)
+ return currency['code']
+ }
+
+ safeMarket (marketId, market = undefined, delimiter = undefined) {
+ if (marketId !== undefined) {
+ if (this.markets_by_id !== undefined && marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId]
+ } else if (delimiter !== undefined) {
+ const [ baseId, quoteId ] = marketId.split (delimiter)
+ const base = this.safeCurrencyCode (baseId)
+ const quote = this.safeCurrencyCode (quoteId)
+ const symbol = base + '/' + quote
+ return {
+ 'id': marketId,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ }
}
}
- if (code === undefined && currency !== undefined) {
- code = currency['code']
+ if (market !== undefined) {
+ return market
}
- return code
+ return {
+ 'id': marketId,
+ 'symbol': marketId,
+ 'base': undefined,
+ 'quote': undefined,
+ 'baseId': undefined,
+ 'quoteId': undefined,
+ }
+ }
+
+ safeSymbol (marketId, market = undefined, delimiter = undefined) {
+ market = this.safeMarket (marketId, market, delimiter)
+ return market['symbol'];
}
filterBySymbol (array, symbol = undefined) {
- return ((symbol !== undefined) ? array.filter (entry => entry.symbol === symbol) : array)
+ return ((symbol !== undefined) ? array.filter ((entry) => entry.symbol === symbol) : array)
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
return Array.isArray (ohlcv) ? ohlcv.slice (0, 6) : ohlcv
}
@@ -4528,7 +3001,7 @@ module.exports = class Exchange {
if (limit && (result.length >= limit)) {
break;
}
- const ohlcv = this.parseOHLCV (ohlcvs[i], market, timeframe, since, limit)
+ const ohlcv = this.parseOHLCV (ohlcvs[i], market)
if (since && (ohlcv[0] < since)) {
continue
}
@@ -4550,8 +3023,9 @@ module.exports = class Exchange {
}
async editOrder (id, symbol, ...args) {
- if (!this.enableRateLimit)
+ if (!this.enableRateLimit) {
throw new ExchangeError (this.id + ' editOrder() requires enableRateLimit = true')
+ }
await this.cancelOrder (id, symbol);
return this.createOrder (symbol, ...args)
}
@@ -4581,23 +3055,23 @@ module.exports = class Exchange {
}
costToPrecision (symbol, cost) {
- return decimalToPrecision (cost, ROUND, this.markets[symbol].precision.price, this.precisionMode)
+ return decimalToPrecision (cost, ROUND, this.markets[symbol].precision.price, this.precisionMode, this.paddingMode)
}
priceToPrecision (symbol, price) {
- return decimalToPrecision (price, ROUND, this.markets[symbol].precision.price, this.precisionMode)
+ return decimalToPrecision (price, ROUND, this.markets[symbol].precision.price, this.precisionMode, this.paddingMode)
}
amountToPrecision (symbol, amount) {
- return decimalToPrecision (amount, TRUNCATE, this.markets[symbol].precision.amount, this.precisionMode)
+ return decimalToPrecision (amount, TRUNCATE, this.markets[symbol].precision.amount, this.precisionMode, this.paddingMode)
}
feeToPrecision (symbol, fee) {
- return decimalToPrecision (fee, ROUND, this.markets[symbol].precision.price, this.precisionMode)
+ return decimalToPrecision (fee, ROUND, this.markets[symbol].precision.price, this.precisionMode, this.paddingMode)
}
currencyToPrecision (currency, fee) {
- return decimalToPrecision (fee, ROUND, this.currencies[currency]['precision'], this.precisionMode);
+ return decimalToPrecision (fee, ROUND, this.currencies[currency]['precision'], this.precisionMode, this.paddingMode);
}
calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) {
@@ -4612,26 +3086,19 @@ module.exports = class Exchange {
}
}
- // ------------------------------------------------------------------------
- // web3 / 0x methods
- static hasWeb3 () {
- return ethUtil && ethAbi
- }
-
checkRequiredDependencies () {
- if (!Exchange.hasWeb3 ()) {
- throw new ExchangeError ('Required dependencies missing: \nnpm i ethereumjs-util ethereumjs-abi --no-save');
- }
+ return
}
soliditySha3 (array) {
// we only support address, uint256, and string solidity types
const encoded = []
- for (const value of array) {
+ for (let i = 0; i < array.length; i++) {
+ const value = array[i]
if (Number.isInteger (value) || value.match (/^[0-9]+$/)) {
encoded.push (this.numberToBE (this.numberToString (value), 32))
} else {
- const noPrefix = Exchange.remove0xPrefix (value)
+ const noPrefix = this.remove0xPrefix (value)
if (noPrefix.length === 40 && noPrefix.toLowerCase ().match (/^[0-9a-f]+$/)) { // check if it is an address
encoded.push (this.base16ToBinary (noPrefix))
} else {
@@ -4643,108 +3110,7 @@ module.exports = class Exchange {
return '0x' + this.hash (concated, 'keccak', 'hex')
}
- getZeroExOrderHash (order) {
- return this.soliditySha3 ([
- order['exchangeContractAddress'], // address
- order['maker'], // address
- order['taker'], // address
- order['makerTokenAddress'], // address
- order['takerTokenAddress'], // address
- order['feeRecipient'], // address
- order['makerTokenAmount'], // uint256
- order['takerTokenAmount'], // uint256
- order['makerFee'], // uint256
- order['takerFee'], // uint256
- order['expirationUnixTimestampSec'], // uint256
- order['salt'], // uint256
- ]);
- }
-
- getZeroExOrderHashV2 (order) {
- // https://github.com/0xProject/0x-monorepo/blob/development/python-packages/order_utils/src/zero_ex/order_utils/__init__.py
- const addressPadding = '000000000000000000000000';
- const header = '1901';
- const domainStructHeader = '91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a2766f0f24618f4c4be1e62e026fb039a20ef96f4495294817d1027ffaa6d1f70e61ead7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5';
- const orderSchemaHash = '770501f88a26ede5c04a20ef877969e961eb11fc13b78aaf414b633da0d4f86f';
-
- const domainStructHash = ethAbi.soliditySHA3 (
- [
- 'bytes',
- 'bytes',
- 'address'
- ],
- [
- Buffer.from (domainStructHeader, 'hex'),
- Buffer.from (addressPadding, 'hex'),
- order['exchangeAddress']
- ]
- );
- const orderStructHash = ethAbi.soliditySHA3 (
- [
- 'bytes',
- 'bytes',
- 'address',
- 'bytes',
- 'address',
- 'bytes',
- 'address',
- 'bytes',
- 'address',
- 'uint256',
- 'uint256',
- 'uint256',
- 'uint256',
- 'uint256',
- 'uint256',
- 'string',
- 'string'
- ],
- [
- Buffer.from (orderSchemaHash, 'hex'),
- Buffer.from (addressPadding, 'hex'),
- order['makerAddress'],
- Buffer.from (addressPadding, 'hex'),
- order['takerAddress'],
- Buffer.from (addressPadding, 'hex'),
- order['feeRecipientAddress'],
- Buffer.from (addressPadding, 'hex'),
- order['senderAddress'],
- order['makerAssetAmount'],
- order['takerAssetAmount'],
- order['makerFee'],
- order['takerFee'],
- order['expirationTimeSeconds'],
- order['salt'],
- ethUtil.keccak (Buffer.from (order['makerAssetData'].slice (2), 'hex')),
- ethUtil.keccak (Buffer.from (order['takerAssetData'].slice (2), 'hex')),
- ]
- );
- return '0x' + ethUtil.keccak (Buffer.concat ([
- Buffer.from (header, 'hex'),
- domainStructHash,
- orderStructHash
- ])).toString ('hex');
- }
-
- signZeroExOrderV2 (order, privateKey) {
- const orderHash = this.getZeroExOrderHashV2 (order);
- const signature = this.signMessage (orderHash, privateKey);
- return this.extend (order, {
- 'orderHash': orderHash,
- 'signature': this.convertECSignatureToSignatureHex (signature),
- })
- }
-
- convertECSignatureToSignatureHex (signature) {
- // https://github.com/0xProject/0x-monorepo/blob/development/packages/order-utils/src/signature_utils.ts
- let v = signature.v;
- if (v !== 27 && v !== 28) {
- v = v + 27;
- }
- return '0x' + v.toString (16) + signature['r'].slice (-64) + signature['s'].slice (-64) + '03'
- }
-
- static remove0xPrefix (hexData) {
+ remove0xPrefix (hexData) {
if (hexData.slice (0, 2) === '0x') {
return hexData.slice (2)
} else {
@@ -4754,7 +3120,7 @@ module.exports = class Exchange {
hashMessage (message) {
// takes a hex encoded message
- const binaryMessage = this.base16ToBinary (Exchange.remove0xPrefix (message))
+ const binaryMessage = this.base16ToBinary (this.remove0xPrefix (message))
const prefix = this.stringToBinary ('\x19Ethereum Signed Message:\n' + binaryMessage.sigBytes)
return '0x' + this.hash (this.binaryConcat (prefix, binaryMessage), 'keccak', 'hex')
}
@@ -4772,6 +3138,13 @@ module.exports = class Exchange {
return this.signHash (this.hashMessage (message), privateKey.slice (-64))
}
+ signMessageString (message, privateKey) {
+ // still takes the input as a hex string
+ // same as above but returns a string instead of an object
+ const signature = this.signMessage (message, privateKey)
+ return signature['r'] + this.remove0xPrefix (signature['s']) + this.binaryToBase16 (this.numberToBE (signature['v']));
+ }
+
oath () {
if (typeof this.twofa !== 'undefined') {
return this.totp (this.twofa)
@@ -4796,8 +3169,7 @@ module.exports = class Exchange {
}
-}).call(this,require("buffer").Buffer)
-},{"../static_dependencies/BN/bn":119,"./errors":9,"./functions":10,"buffer":178}],8:[function(require,module,exports){
+},{"../static_dependencies/BN/bn":123,"./errors":7,"./functions":8}],6:[function(require,module,exports){
'use strict';
const errorHierarchy = {
@@ -4843,7 +3215,7 @@ const errorHierarchy = {
module.exports = errorHierarchy;
-},{}],9:[function(require,module,exports){
+},{}],7:[function(require,module,exports){
'use strict';
const errorHierarchy = require ('./errorHierarchy.js')
@@ -4896,7 +3268,7 @@ module.exports = subclass (
errorHierarchy
)
-},{"./errorHierarchy.js":8}],10:[function(require,module,exports){
+},{"./errorHierarchy.js":6}],8:[function(require,module,exports){
'use strict';
/* ------------------------------------------------------------------------ */
@@ -4926,17 +3298,19 @@ module.exports = unCamelCasePropertyNames (Object.assign ({}
/* ------------------------------------------------------------------------ */
-},{"./functions/crypto":11,"./functions/encode":12,"./functions/generic":13,"./functions/misc":14,"./functions/number":15,"./functions/platform":16,"./functions/string":17,"./functions/throttle":18,"./functions/time":19,"./functions/type":20}],11:[function(require,module,exports){
+},{"./functions/crypto":9,"./functions/encode":10,"./functions/generic":11,"./functions/misc":12,"./functions/number":13,"./functions/platform":14,"./functions/string":15,"./functions/throttle":16,"./functions/time":17,"./functions/type":18}],9:[function(require,module,exports){
'use strict'
/* ------------------------------------------------------------------------ */
const CryptoJS = require ('../../static_dependencies/crypto-js/crypto-js')
const { capitalize } = require ('./string')
-const { stringToBase64, utf16ToBase64, urlencodeBase64 } = require ('./encode')
+const { stringToBase64, urlencodeBase64 } = require ('./encode')
const NodeRSA = require ('./../../static_dependencies/node-rsa/NodeRSA')
-const { numberToLE } = require ('./encode')
-const EC = require ('./../../static_dependencies/elliptic/lib/elliptic').ec
+const { binaryToBase58, byteArrayToWordArray } = require ('./encode')
+const elliptic = require ('./../../static_dependencies/elliptic/lib/elliptic')
+const EC = elliptic.ec
+const EDDSA = elliptic.eddsa
const { ArgumentsRequired } = require ('./../errors')
const BN = require ('../../static_dependencies/BN/bn.js')
@@ -5025,6 +3399,14 @@ function ecdsa (request, secret, algorithm = 'p256', hashFunction = undefined, f
}
}
+
+function eddsa (request, secret, algorithm = 'ed25519') {
+ // used for waves.exchange (that's why the output is base58)
+ const curve = new EDDSA (algorithm)
+ const signature = curve.signModified (request, secret)
+ return binaryToBase58 (byteArrayToWordArray (signature.toBytes ()))
+}
+
/* ------------------------------------------------------------------------ */
const totp = (secret) => {
@@ -5071,11 +3453,12 @@ module.exports = {
totp,
rsa,
ecdsa,
+ eddsa,
}
/* ------------------------------------------------------------------------ */
-},{"../../static_dependencies/BN/bn.js":119,"../../static_dependencies/crypto-js/crypto-js":120,"./../../static_dependencies/elliptic/lib/elliptic":121,"./../../static_dependencies/node-rsa/NodeRSA":136,"./../errors":9,"./encode":12,"./string":17}],12:[function(require,module,exports){
+},{"../../static_dependencies/BN/bn.js":123,"../../static_dependencies/crypto-js/crypto-js":124,"./../../static_dependencies/elliptic/lib/elliptic":125,"./../../static_dependencies/node-rsa/NodeRSA":143,"./../errors":7,"./encode":10,"./string":15}],10:[function(require,module,exports){
"use strict";
/* ------------------------------------------------------------------------ */
@@ -5084,6 +3467,14 @@ const CryptoJS = require ('../../static_dependencies/crypto-js/crypto-js')
const qs = require ('../../static_dependencies/qs/index')
const BN = require ('../../static_dependencies/BN/bn')
+
+/* ------------------------------------------------------------------------ */
+
+// global vars for base58 encoding
+const base58Alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
+let base58Decoder = null
+let base58Encoder = null
+
/* ------------------------------------------------------------------------ */
module.exports =
@@ -5097,14 +3488,8 @@ module.exports =
((object[0] === '{') || (object[0] === '['))
)
- , stringToBinary (str) {
- const arr = new Uint8Array (str.length)
- for (let i = 0; i < str.length; i++) { arr[i] = str.charCodeAt (i); }
- return CryptoJS.lib.WordArray.create (arr)
- }
-
+ , stringToBinary: string => CryptoJS.enc.Latin1.parse (string)
, stringToBase64: string => CryptoJS.enc.Latin1.parse (string).toString (CryptoJS.enc.Base64)
- , utf16ToBase64: string => CryptoJS.enc.Utf16 .parse (string).toString (CryptoJS.enc.Base64)
, base64ToBinary: string => CryptoJS.enc.Base64.parse (string)
, base64ToString: string => CryptoJS.enc.Base64.parse (string).toString (CryptoJS.enc.Utf8)
, binaryToBase64: binary => binary.toString (CryptoJS.enc.Base64)
@@ -5134,9 +3519,54 @@ module.exports =
const hexArray = new BN (n).toArray ('be', padding)
return byteArrayToWordArray (hexArray)
}
+
+ , base58ToBinary: (string) => {
+ if (!base58Decoder) {
+ base58Decoder = {}
+ base58Encoder = {}
+ for (let i = 0; i < 58; i++) {
+ const c = base58Alphabet[i]
+ const bigNum = new BN (i)
+ base58Decoder[c] = bigNum
+ base58Encoder[bigNum] = c
+ }
+ }
+ let result = new BN (0)
+ const base = new BN (58)
+ for (let i = 0; i < string.length; i++) {
+ const character = string[i]
+ result.imul (base)
+ result.iadd (base58Decoder[character])
+ }
+ return byteArrayToWordArray (result.toArray ('be'))
+ }
+
+ , binaryToBase58: (wordArray) => {
+ if (!base58Encoder) {
+ base58Decoder = {}
+ base58Encoder = {}
+ for (let i = 0; i < 58; i++) {
+ const c = base58Alphabet[i]
+ const bigNum = new BN (i)
+ base58Decoder[c] = bigNum
+ base58Encoder[bigNum] = c
+ }
+ }
+ const base = new BN (58)
+ // hex is only compatible encoding between cryptojs and BN
+ const hexString = wordArray.toString (CryptoJS.enc.Hex)
+ let result = new BN (hexString, 16)
+ let string = []
+ while (!result.isZero ()) {
+ const { div, mod } = result.divmod (base)
+ result = div
+ string.push (base58Encoder[mod])
+ }
+ return string.reverse ().join ('')
+ }
}
-function byteArrayToWordArray(ba) {
+function byteArrayToWordArray (ba) {
const wa = []
for (let i = 0; i < ba.length; i++) {
wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i)
@@ -5148,43 +3578,34 @@ module.exports['byteArrayToWordArray'] = byteArrayToWordArray
/* ------------------------------------------------------------------------ */
-},{"../../static_dependencies/BN/bn":119,"../../static_dependencies/crypto-js/crypto-js":120,"../../static_dependencies/qs/index":152}],13:[function(require,module,exports){
+},{"../../static_dependencies/BN/bn":123,"../../static_dependencies/crypto-js/crypto-js":124,"../../static_dependencies/qs/index":159}],11:[function(require,module,exports){
"use strict";
-/* ------------------------------------------------------------------------ */
+// ----------------------------------------------------------------------------
const { isObject, isNumber, isDictionary, isArray } = require ('./type')
-/* ------------------------------------------------------------------------ */
+// ----------------------------------------------------------------------------
const keys = Object.keys
-
- , values = x => !isArray (x) // don't copy arrays if they're already arrays!
- ? Object.values (x)
- : x
-
- , index = x => new Set (values (x))
-
+ , values = (x) => ((!isArray (x)) ? Object.values (x) : x) // don't copy arrays if they're already arrays
+ , index = (x) => new Set (values (x))
, extend = (...args) => Object.assign ({}, ...args) // NB: side-effect free
+ , clone = (x) => (isArray (x) ? Array.from (x) : extend (x)) // clone arrays or objects
- , clone = x => isArray (x)
- ? Array.from (x) // clones arrays
- : extend (x) // clones objects
+// ----------------------------------------------------------------------------
-/* ------------------------------------------------------------------------ */
-
-module.exports =
-
- { keys
+module.exports = {
+ keys
, values
, extend
, clone
, index
- , ordered: x => x // a stub to keep assoc keys in order (in JS it does nothing, it's mostly for Python)
- , unique: x => Array.from (index (x))
+ , ordered: (x) => x // a stub to keep assoc keys in order (in JS it does nothing, it's mostly for Python)
+ , unique: (x) => Array.from (index (x))
, arrayConcat: (a, b) => a.concat (b)
- /* ............................................. */
+ // ------------------------------------------------------------------------
, inArray (needle, haystack) {
@@ -5197,12 +3618,13 @@ module.exports =
}
, isEmpty (object) {
- if (!object)
- return true;
+ if (!object) {
+ return true
+ }
return (Array.isArray (object) ? object : Object.keys (object)).length < 1;
}
-/* ............................................. */
+ // ------------------------------------------------------------------------
, keysort (x, out = {}) {
@@ -5212,55 +3634,57 @@ module.exports =
return out
}
-/* ............................................. */
+ // ------------------------------------------------------------------------
/*
- Accepts a map/array of objects and a key name to be used as an index:
- array = [
- { someKey: 'value1', anotherKey: 'anotherValue1' },
- { someKey: 'value2', anotherKey: 'anotherValue2' },
- { someKey: 'value3', anotherKey: 'anotherValue3' },
- ]
- key = 'someKey'
+ Accepts a map/array of objects and a key name to be used as an index:
+ array = [
+ { someKey: 'value1', anotherKey: 'anotherValue1' },
+ { someKey: 'value2', anotherKey: 'anotherValue2' },
+ { someKey: 'value3', anotherKey: 'anotherValue3' },
+ ]
+ key = 'someKey'
- Returns a map:
- {
- value1: { someKey: 'value1', anotherKey: 'anotherValue1' },
- value2: { someKey: 'value2', anotherKey: 'anotherValue2' },
- value3: { someKey: 'value3', anotherKey: 'anotherValue3' },
- }
+ Returns a map:
+ {
+ value1: { someKey: 'value1', anotherKey: 'anotherValue1' },
+ value2: { someKey: 'value2', anotherKey: 'anotherValue2' },
+ value3: { someKey: 'value3', anotherKey: 'anotherValue3' },
+ }
*/
, indexBy (x, k, out = {}) {
- for (const v of values (x))
- if (k in v)
+ for (const v of values (x)) {
+ if (k in v) {
out[v[k]] = v
+ }
+ }
return out
}
-/* ............................................. */
+ // ------------------------------------------------------------------------
/*
- Accepts a map/array of objects and a key name to be used as a grouping parameter:
- array = [
- { someKey: 'value1', anotherKey: 'anotherValue1' },
- { someKey: 'value1', anotherKey: 'anotherValue2' },
- { someKey: 'value3', anotherKey: 'anotherValue3' },
- ]
- key = 'someKey'
-
- Returns a map:
- {
- value1: [
+ Accepts a map/array of objects and a key name to be used as a grouping parameter:
+ array = [
{ someKey: 'value1', anotherKey: 'anotherValue1' },
{ someKey: 'value1', anotherKey: 'anotherValue2' },
- ]
- value3: [
- { someKey: 'value3', anotherKey: 'anotherValue3' }
- ],
- }
+ { someKey: 'value3', anotherKey: 'anotherValue3' },
+ ]
+ key = 'someKey'
+
+ Returns a map:
+ {
+ value1: [
+ { someKey: 'value1', anotherKey: 'anotherValue1' },
+ { someKey: 'value1', anotherKey: 'anotherValue2' },
+ ]
+ value3: [
+ { someKey: 'value3', anotherKey: 'anotherValue3' }
+ ],
+ }
*/
, groupBy (x, k, out = {}) {
@@ -5275,61 +3699,68 @@ module.exports =
return out
}
-/* ............................................. */
+ // ------------------------------------------------------------------------
/*
- Accepts a map/array of objects, a key name and a key value to be used as a filter:
- array = [
- { someKey: 'value1', anotherKey: 'anotherValue1' },
- { someKey: 'value2', anotherKey: 'anotherValue2' },
- { someKey: 'value3', anotherKey: 'anotherValue3' },
- ]
- key = 'someKey'
- value = 'value1'
+ Accepts a map/array of objects, a key name and a key value to be used as a filter:
+ array = [
+ { someKey: 'value1', anotherKey: 'anotherValue1' },
+ { someKey: 'value2', anotherKey: 'anotherValue2' },
+ { someKey: 'value3', anotherKey: 'anotherValue3' },
+ ]
+ key = 'someKey'
+ value = 'value1'
- Returns an array:
- [
- value1: { someKey: 'value1', anotherKey: 'anotherValue1' },
- ]
+ Returns an array:
+ [
+ value1: { someKey: 'value1', anotherKey: 'anotherValue1' },
+ ]
*/
, filterBy (x, k, value = undefined, out = []) {
- for (const v of values (x))
- if (v[k] === value)
+ for (const v of values (x)) {
+ if (v[k] === value) {
out.push (v)
-
- return out
- }
-
-/* ............................................. */
-
- , sortBy: (array, // NB: MUTATES ARRAY!
- key,
- descending = false,
- direction = descending ? -1 : 1) => array.sort ((a, b) =>
- ((a[key] < b[key]) ? -direction :
- ((a[key] > b[key]) ? direction : 0)))
-
-/* ............................................. */
-
- , flatten: function flatten (x, out = []) {
-
- for (const v of x) {
- if (isArray (v)) flatten (v, out)
- else out.push (v)
+ }
}
return out
}
-/* ............................................. */
+ // ------------------------------------------------------------------------
+ // NB: MUTATES ARRAY!
- , pluck: (x, k) => values (x)
- .filter (v => k in v)
- .map (v => v[k])
+ , sortBy: (array, key, descending = false, direction = descending ? -1 : 1) => array.sort ((a, b) => {
+ if (a[key] < b[key]) {
+ return -direction
+ } else if (a[key] > b[key]) {
+ return direction
+ } else {
+ return 0
+ }
+ })
-/* ............................................. */
+ // ------------------------------------------------------------------------
+
+ , flatten: function flatten (x, out = []) {
+
+ for (const v of x) {
+ if (isArray (v)) {
+ flatten (v, out)
+ } else {
+ out.push (v)
+ }
+ }
+
+ return out
+ }
+
+ // ------------------------------------------------------------------------
+
+ , pluck: (x, k) => values (x).filter ((v) => k in v).map ((v) => v[k])
+
+ // ------------------------------------------------------------------------
, omit (x, ...args) {
@@ -5338,15 +3769,13 @@ module.exports =
const out = clone (x)
for (const k of args) {
-
if (isArray (k)) { // omit (x, ['a', 'b'])
-
for (const kk of k) {
delete out[kk]
}
+ } else {
+ delete out[k] // omit (x, 'a', 'b')
}
-
- else delete out[k] // omit (x, 'a', 'b')
}
return out
@@ -5355,24 +3784,22 @@ module.exports =
return x
}
-/* ............................................. */
+ // ------------------------------------------------------------------------
, sum (...xs) {
const ns = xs.filter (isNumber) // leave only numbers
- return (ns.length > 0)
- ? ns.reduce ((a, b) => a + b, 0)
- : undefined
+ return (ns.length > 0) ? ns.reduce ((a, b) => a + b, 0) : undefined
}
-/* ............................................. */
+ // ------------------------------------------------------------------------
, deepExtend: function deepExtend (...xs) {
let out = undefined
for (const x of xs) {
if (isDictionary (x)) {
- if (!isObject (out)) {
+ if (!isDictionary (out)) {
out = {}
}
for (const k in x) {
@@ -5385,15 +3812,15 @@ module.exports =
return out
}
-/* ------------------------------------------------------------------------ */
+// ----------------------------------------------------------------------------
}
-},{"./type":20}],14:[function(require,module,exports){
+},{"./type":18}],12:[function(require,module,exports){
'use strict';
const { ROUND_UP, ROUND_DOWN } = require ('./number')
-const { NotSupported } = require ('./../errors')
+const { NotSupported } = require ('../errors')
//-------------------------------------------------------------------------
// converts timeframe to seconds
@@ -5440,8 +3867,9 @@ const buildOHLCVC = (trades, timeframe = '1m', since = -Infinity, limit = Infini
for (let i = 0; i <= oldest; i++) {
const trade = trades[i];
- if (trade.timestamp < since)
+ if (trade.timestamp < since) {
continue;
+ }
const openingTime = Math.floor (trade.timestamp / ms) * ms; // shift to the edge of m/h/d (but not M)
const candle = ohlcvs.length - 1;
@@ -5492,6 +3920,10 @@ const implodeParams = (string, params) => {
return string
}
+function vwap (baseVolume, quoteVolume) {
+ return ((baseVolume !== undefined) && (quoteVolume !== undefined) && (baseVolume > 0)) ? (quoteVolume / baseVolume) : undefined
+}
+
/* ------------------------------------------------------------------------ */
module.exports = {
@@ -5507,7 +3939,7 @@ module.exports = {
}
}
- return Object.keys (result).map (price => [parseFloat (price), parseFloat (result[price])])
+ return Object.keys (result).map ((price) => [parseFloat (price), parseFloat (result[price])])
},
parseTimeframe,
@@ -5517,12 +3949,14 @@ module.exports = {
ROUND_DOWN,
implodeParams,
- extractParams
+ extractParams,
+
+ vwap,
}
/* ------------------------------------------------------------------------ */
-},{"./../errors":9,"./number":15}],15:[function(require,module,exports){
+},{"../errors":7,"./number":13}],13:[function(require,module,exports){
'use strict'
/* ------------------------------------------------------------------------
@@ -5572,11 +4006,12 @@ function numberToString (x) { // avoids scientific notation for too large and to
const s = x.toString ()
if (Math.abs (x) < 1.0) {
- const e = parseInt (s.split ('e-')[1])
+ const n_e = s.split ('e-')
+ const n = n_e[0].replace ('.', '')
+ const e = parseInt (n_e[1])
const neg = (s[0] === '-')
if (e) {
- x *= Math.pow (10, e - 1)
- x = (neg ? '-' : '') + '0.' + (new Array (e)).join ('0') + x.toString ().substring (neg ? 3 : 2)
+ x = (neg ? '-' : '') + '0.' + (new Array (e)).join ('0') + n.substring (neg)
return x
}
} else {
@@ -5590,7 +4025,7 @@ function numberToString (x) { // avoids scientific notation for too large and to
return m[0] + m[1] + (new Array (e + 1)).join ('0')
}
}
- return s;
+ return s
}
//-----------------------------------------------------------------------------
@@ -5620,10 +4055,13 @@ const decimalToPrecision = (x, roundingMode
, countingMode = DECIMAL_PLACES
, paddingMode = NO_PADDING) => {
- if (numPrecisionDigits < 0) {
- if (countingMode === TICK_SIZE) {
- throw new Error (`TICK_SIZE cant be used with negative numPrecisionDigits`)
+ if (countingMode === TICK_SIZE) {
+ if (numPrecisionDigits <= 0) {
+ throw new Error ('TICK_SIZE cant be used with negative or zero numPrecisionDigits')
}
+ }
+
+ if (numPrecisionDigits < 0) {
const toNearest = Math.pow (10, -numPrecisionDigits)
if (roundingMode === ROUND) {
return (toNearest * decimalToPrecision (x / toNearest, roundingMode, 0, countingMode, paddingMode)).toString ()
@@ -5635,7 +4073,7 @@ const decimalToPrecision = (x, roundingMode
/* handle tick size */
if (countingMode === TICK_SIZE) {
- const precisionDigitsString = decimalToPrecision (numPrecisionDigits, ROUND, 100, DECIMAL_PLACES, NO_PADDING)
+ const precisionDigitsString = decimalToPrecision (numPrecisionDigits, ROUND, 22, DECIMAL_PLACES, NO_PADDING)
const newNumPrecisionDigits = precisionFromString (precisionDigitsString)
let missing = x % numPrecisionDigits
// See: https://github.com/ccxt/ccxt/pull/6486
@@ -5859,7 +4297,7 @@ module.exports = {
/* ------------------------------------------------------------------------ */
-},{}],16:[function(require,module,exports){
+},{}],14:[function(require,module,exports){
(function (process){
"use strict";
@@ -5900,7 +4338,7 @@ module.exports = {
defaultFetch,
}
}).call(this,require('_process'))
-},{"../../static_dependencies/fetch-ponyfill/fetch-node":134,"_process":200}],17:[function(require,module,exports){
+},{"../../static_dependencies/fetch-ponyfill/fetch-node":141,"_process":207}],15:[function(require,module,exports){
"use strict";
/* ------------------------------------------------------------------------ */
@@ -5923,7 +4361,7 @@ module.exports =
/* ------------------------------------------------------------------------ */
-},{}],18:[function(require,module,exports){
+},{}],16:[function(require,module,exports){
"use strict";
/* ------------------------------------------------------------------------ */
@@ -5989,7 +4427,7 @@ module.exports = {
/* ------------------------------------------------------------------------ */
-},{"./time":19}],19:[function(require,module,exports){
+},{"./time":17}],17:[function(require,module,exports){
'use strict';
/* ------------------------------------------------------------------------ */
@@ -5998,6 +4436,17 @@ const now = Date.now // TODO: figure out how to utilize performance.now () prope
const microseconds = () => now () * 1000 // TODO: utilize performance.now for that purpose
const milliseconds = now
const seconds = () => Math.floor (now () / 1000)
+const uuidv1 = () => {
+ const biasSeconds = 12219292800 // seconds from 15th Oct 1572 to Jan 1st 1970
+ const bias = biasSeconds * 10000000 // in hundreds of nanoseconds
+ const time = microseconds () * 10 + bias
+ const timeHex = time.toString (16)
+ const arranged = timeHex.slice (7, 15) + timeHex.slice (3, 7) + '1' + timeHex.slice (0, 3)
+ // these should be random, but we're not making more than 10 requests per microsecond so who cares
+ const clockId = '9696' // a 14 bit number
+ const macAddress = 'ff'.repeat (6)
+ return arranged + clockId + macAddress
+}
/* ------------------------------------------------------------------------ */
@@ -6107,6 +4556,10 @@ const parseDate = (x) => {
return parse8601 (x);
}
+const rfc2616 = (timestamp = undefined) => {
+ return new Date (timestamp).toUTCString ();
+}
+
const mdy = (timestamp, infix = '-') => {
infix = infix || ''
const date = new Date (timestamp)
@@ -6154,6 +4607,8 @@ module.exports =
, seconds
, iso8601
, parse8601
+ , rfc2616
+ , uuidv1
, parseDate
, mdy
, ymd
@@ -6176,7 +4631,7 @@ module.exports =
/* ------------------------------------------------------------------------ */
-},{}],20:[function(require,module,exports){
+},{}],18:[function(require,module,exports){
"use strict";
/* ------------------------------------------------------------------------ */
@@ -6185,9 +4640,10 @@ const isNumber = Number.isFinite
, isInteger = Number.isInteger
, isArray = Array.isArray
, hasProps = o => ((o !== undefined) && (o !== null))
- , isString = s => (typeof s === 'string')
+ , isString = s => (typeof s === 'string')
, isObject = o => ((o !== null) && (typeof o === 'object'))
- , isDictionary = o => (isObject (o) && !isArray (o))
+ , isRegExp = o => (o instanceof RegExp)
+ , isDictionary = o => (isObject (o) && (Object.getPrototypeOf (o) === Object.prototype) && !isArray (o) && !isRegExp (o))
, isStringCoercible = x => ((hasProps (x) && x.toString) || isNumber (x))
/* ............................................. */
@@ -6243,7 +4699,7 @@ module.exports = {
/* ------------------------------------------------------------------------ */
-},{}],21:[function(require,module,exports){
+},{}],19:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -6258,20 +4714,22 @@ module.exports = class bcex extends Exchange {
return this.deepExtend (super.describe (), {
'id': 'bcex',
'name': 'BCEX',
- 'countries': [ 'CN', 'CA' ],
+ 'countries': [ 'CN', 'HK' ],
'version': '1',
'has': {
- 'fetchBalance': true,
- 'fetchMarkets': true,
- 'createOrder': true,
'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': 'emulated',
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrders': true,
+ 'fetchOrderBook': true,
'fetchTicker': true,
'fetchTickers': false,
'fetchTrades': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchClosedOrders': 'emulated',
- 'fetchOpenOrders': true,
'fetchTradingLimits': true,
},
'urls': {
@@ -6342,6 +4800,10 @@ module.exports = class bcex extends Exchange {
'参数非法': InvalidOrder, // {'code': 1, 'msg': '参数非法'} - 'Parameter illegal'
'订单信息不存在': OrderNotFound, // {'code': 1, 'msg': '订单信息不存在'} - 'Order information does not exist'
},
+ 'commonCurrencies': {
+ 'UNI': 'UNI COIN',
+ 'PNT': 'Penta',
+ },
'options': {
'limits': {
// hardcoding is deprecated, using these predefined values is not recommended, use loadTradingLimits instead
@@ -6798,8 +5260,10 @@ module.exports = class bcex extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -6924,7 +5388,7 @@ module.exports = class bcex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],22:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],20:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -6958,13 +5422,13 @@ module.exports = class bequant extends hitbtc {
}
};
-},{"./hitbtc":90}],23:[function(require,module,exports){
+},{"./hitbtc":89}],21:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, AccountSuspended, ArgumentsRequired, AuthenticationError, DDoSProtection, ExchangeNotAvailable, InvalidOrder, OrderNotFound, PermissionDenied, InsufficientFunds } = require ('./base/errors');
+const { ExchangeError, AccountSuspended, ArgumentsRequired, AuthenticationError, DDoSProtection, ExchangeNotAvailable, InvalidOrder, OrderNotFound, PermissionDenied, InsufficientFunds, BadSymbol } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -6975,22 +5439,29 @@ module.exports = class bibox extends Exchange {
'name': 'Bibox',
'countries': [ 'CN', 'US', 'KR' ],
'version': 'v1',
+ 'hostname': 'bibox365.com',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'publicAPI': false,
+ 'createMarketOrder': false, // or they will return https://github.com/ccxt/ccxt/issues/2338
+ 'createOrder': true,
'fetchBalance': true,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
+ 'fetchClosedOrders': true,
'fetchCurrencies': true,
+ 'fetchDeposits': true,
'fetchDepositAddress': true,
'fetchFundingFees': true,
- 'fetchTickers': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
- 'createMarketOrder': false, // or they will return https://github.com/ccxt/ccxt/issues/2338
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ 'publicAPI': false,
'withdraw': true,
},
'timeframes': {
@@ -7008,13 +5479,13 @@ module.exports = class bibox extends Exchange {
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/51840849/77257418-3262b000-6c85-11ea-8fb8-20bdf20b3592.jpg',
- 'api': 'https://api.bibox.com',
- 'www': 'https://www.bibox.com',
+ 'api': 'https://api.{hostname}',
+ 'www': 'https://www.bibox365.com',
'doc': [
'https://biboxcom.github.io/en/',
],
'fees': 'https://bibox.zendesk.com/hc/en-us/articles/360002336133',
- 'referral': 'https://w2.bibox.com/login/register?invite_code=05Kj3I',
+ 'referral': 'https://w2.bibox365.com/login/register?invite_code=05Kj3I',
},
'api': {
'public': {
@@ -7066,12 +5537,15 @@ module.exports = class bibox extends Exchange {
'2068': InvalidOrder, // The number of orders can not be less than
'2085': InvalidOrder, // Order quantity is too small
'3012': AuthenticationError, // invalid apiKey
+ '3016': BadSymbol, // Trading pair error
'3024': PermissionDenied, // wrong apikey permissions
'3025': AuthenticationError, // signature failed
'4000': ExchangeNotAvailable, // current network is unstable
'4003': DDoSProtection, // server busy please try again later
},
'commonCurrencies': {
+ 'BOX': 'DefiBox',
+ 'BPT': 'BlockPool Token',
'KEY': 'Bihu',
'MTC': 'MTC Mesh Network', // conflict with MTC Docademic doc.com Token https://github.com/ccxt/ccxt/issues/6081 https://github.com/ccxt/ccxt/issues/3025
'PAI': 'PCHAIN',
@@ -7232,7 +5706,8 @@ module.exports = class bibox extends Exchange {
};
const response = await this.publicGetMdata (this.extend (request, params));
const tickers = this.parseTickers (response['result'], symbols);
- return this.indexBy (tickers, 'symbol');
+ const result = this.indexBy (tickers, 'symbol');
+ return this.filterByArray (result, 'symbol', symbols);
}
parseTrade (trade, market = undefined) {
@@ -7275,7 +5750,7 @@ module.exports = class bibox extends Exchange {
}
if (feeCost !== undefined) {
fee = {
- 'cost': feeCost,
+ 'cost': -feeCost,
'currency': feeCurrency,
'rate': feeRate,
};
@@ -7326,9 +5801,19 @@ module.exports = class bibox extends Exchange {
return this.parseOrderBook (response['result'], this.safeFloat (response['result'], 'update_time'), 'bids', 'asks', 'price', 'volume');
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "time":1591448220000,
+ // "open":"0.02507029",
+ // "high":"0.02507029",
+ // "low":"0.02506349",
+ // "close":"0.02506349",
+ // "vol":"5.92000000"
+ // }
+ //
return [
- ohlcv['time'],
+ this.safeInteger (ohlcv, 'time'),
this.safeFloat (ohlcv, 'open'),
this.safeFloat (ohlcv, 'high'),
this.safeFloat (ohlcv, 'low'),
@@ -7347,7 +5832,19 @@ module.exports = class bibox extends Exchange {
'size': limit,
};
const response = await this.publicGetMdata (this.extend (request, params));
- return this.parseOHLCVs (response['result'], market, timeframe, since, limit);
+ //
+ // {
+ // "result":[
+ // {"time":1591448220000,"open":"0.02507029","high":"0.02507029","low":"0.02506349","close":"0.02506349","vol":"5.92000000"},
+ // {"time":1591448280000,"open":"0.02506449","high":"0.02506975","low":"0.02506108","close":"0.02506843","vol":"5.72000000"},
+ // {"time":1591448340000,"open":"0.02506698","high":"0.02506698","low":"0.02506452","close":"0.02506519","vol":"4.86000000"},
+ // ],
+ // "cmd":"kline",
+ // "ver":"1.1"
+ // }
+ //
+ const result = this.safeValue (response, 'result', []);
+ return this.parseOHLCVs (result, market, timeframe, since, limit);
}
async fetchCurrencies (params = {}) {
@@ -7359,6 +5856,52 @@ module.exports = class bibox extends Exchange {
'body': {},
};
const response = await this.privatePostTransfer (this.extend (request, params));
+ //
+ // {
+ // "result":[
+ // {
+ // "result":[
+ // {
+ // "totalBalance":"14.57582269",
+ // "balance":"14.57582269",
+ // "freeze":"0.00000000",
+ // "id":60,
+ // "symbol":"USDT",
+ // "icon_url":"/appimg/USDT_icon.png",
+ // "describe_url":"[{\"lang\":\"zh-cn\",\"link\":\"https://bibox.zendesk.com/hc/zh-cn/articles/115004798234\"},{\"lang\":\"en-ww\",\"link\":\"https://bibox.zendesk.com/hc/en-us/articles/115004798234\"}]",
+ // "name":"USDT",
+ // "enable_withdraw":1,
+ // "enable_deposit":1,
+ // "enable_transfer":1,
+ // "confirm_count":2,
+ // "is_erc20":1,
+ // "forbid_info":null,
+ // "describe_summary":"[{\"lang\":\"zh-cn\",\"text\":\"USDT 是 Tether 公司推出的基于稳定价值货币美元(USD)的代币 Tether USD(简称USDT),1USDT=1美元,用户可以随时使用 USDT 与 USD 进行1:1的兑换。\"},{\"lang\":\"en-ww\",\"text\":\"USDT is a cryptocurrency asset issued on the Bitcoin blockchain via the Omni Layer Protocol. Each USDT unit is backed by a U.S Dollar held in the reserves of the Tether Limited and can be redeemed through the Tether Platform.\"}]",
+ // "total_amount":4776930644,
+ // "supply_amount":4642367414,
+ // "price":"--",
+ // "contract_father":"OMNI",
+ // "supply_time":"--",
+ // "comment":null,
+ // "contract":"31",
+ // "original_decimals":8,
+ // "deposit_type":0,
+ // "hasCobo":0,
+ // "BTCValue":"0.00126358",
+ // "CNYValue":"100.93381445",
+ // "USDValue":"14.57524654",
+ // "children":[
+ // {"type":"OMNI","symbol":"USDT","enable_deposit":1,"enable_withdraw":1,"confirm_count":2},
+ // {"type":"TRC20","symbol":"tUSDT","enable_deposit":1,"enable_withdraw":1,"confirm_count":20},
+ // {"type":"ERC20","symbol":"eUSDT","enable_deposit":1,"enable_withdraw":1,"confirm_count":25}
+ // ]
+ // },
+ // ],
+ // "cmd":"transfer/coinList"
+ // }
+ // ]
+ // }
+ //
const currencies = this.safeValue (response, 'result');
const result = {};
for (let i = 0; i < currencies.length; i++) {
@@ -7680,8 +6223,10 @@ module.exports = class bibox extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': average,
@@ -7868,7 +6413,7 @@ module.exports = class bibox extends Exchange {
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- let url = this.urls['api'] + '/' + this.version + '/' + path;
+ let url = this.implodeParams (this.urls['api'], { 'hostname': this.hostname }) + '/' + this.version + '/' + path;
const cmds = this.json ([ params ]);
if (api === 'public') {
if (method !== 'GET') {
@@ -7928,7 +6473,7 @@ module.exports = class bibox extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],24:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],22:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -7948,16 +6493,23 @@ module.exports = class bigone extends Exchange {
'rateLimit': 1200, // 500 request per 10 minutes
'has': {
'cancelAllOrders': true,
- 'createMarketOrder': false,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrders': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchWithdrawals': true,
'withdraw': true,
},
@@ -8068,6 +6620,7 @@ module.exports = class bigone extends Exchange {
},
},
'commonCurrencies': {
+ 'MBN': 'Mobilian Coin',
'ONE': 'BigONE Token',
},
});
@@ -8178,24 +6731,9 @@ module.exports = class bigone extends Exchange {
// "daily_change":"-0.000182"
// }
//
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (ticker, 'asset_pair_name');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
- const timestamp = this.milliseconds ();
+ const marketId = this.safeString (ticker, 'asset_pair_name');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const timestamp = undefined;
const close = this.safeFloat (ticker, 'close');
const bid = this.safeValue (ticker, 'bid', {});
const ask = this.safeValue (ticker, 'ask', {});
@@ -8294,7 +6832,21 @@ module.exports = class bigone extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetPing (params);
+ //
+ // {
+ // "data": {
+ // "timestamp": 1527665262168391000
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const timestamp = this.safeInteger (data, 'timestamp');
+ return parseInt (timestamp / 1000000);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -8371,20 +6923,7 @@ module.exports = class bigone extends Exchange {
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'amount');
const marketId = this.safeString (trade, 'asset_pair_name');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
let cost = undefined;
if (amount !== undefined) {
if (price !== undefined) {
@@ -8515,7 +7054,7 @@ module.exports = class bigone extends Exchange {
return this.parseTrades (trades, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// close: '0.021562',
@@ -8576,8 +7115,8 @@ module.exports = class bigone extends Exchange {
// ]
// }
//
- const ohlcvs = this.safeValue (response, 'data', []);
- return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async fetchBalance (params = {}) {
@@ -8623,23 +7162,8 @@ module.exports = class bigone extends Exchange {
// }
//
const id = this.safeString (order, 'id');
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'asset_pair_name');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'asset_pair_name');
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const price = this.safeFloat (order, 'price');
const amount = this.safeFloat (order, 'amount');
@@ -8672,8 +7196,10 @@ module.exports = class bigone extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': undefined,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': average,
@@ -8689,12 +7215,34 @@ module.exports = class bigone extends Exchange {
await this.loadMarkets ();
const market = this.market (symbol);
side = (side === 'buy') ? 'BID' : 'ASK';
+ const uppercaseType = type.toUpperCase ();
const request = {
'asset_pair_name': market['id'], // asset pair name BTC-USDT, required
'side': side, // order side one of "ASK"/"BID", required
'amount': this.amountToPrecision (symbol, amount), // order amount, string, required
- 'price': this.priceToPrecision (symbol, price), // order price, string, required
+ // 'price': this.priceToPrecision (symbol, price), // order price, string, required
+ 'type': uppercaseType,
+ // 'operator': 'GTE', // stop orders only, GTE greater than and equal, LTE less than and equal
+ // 'immediate_or_cancel': false, // limit orders only, must be false when post_only is true
+ // 'post_only': false, // limit orders only, must be false when immediate_or_cancel is true
};
+ if (uppercaseType === 'LIMIT') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ } else {
+ const isStopLimit = (uppercaseType === 'STOP_LIMIT');
+ const isStopMarket = (uppercaseType === 'STOP_MARKET');
+ if (isStopLimit || isStopMarket) {
+ const stopPrice = this.safeFloat2 (params, 'stop_price', 'stopPrice');
+ if (stopPrice === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder requires a stop_price parameter');
+ }
+ request['stop_price'] = this.priceToPrecision (symbol, stopPrice);
+ params = this.omit (params, [ 'stop_price', 'stopPrice' ]);
+ }
+ if (isStopLimit) {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ }
const response = await this.privatePostOrders (this.extend (request, params));
//
// {
@@ -9002,6 +7550,24 @@ module.exports = class bigone extends Exchange {
// "txid": "0x4643bb6b393ac20a6175c713175734a72517c63d6f73a3ca90a15356f2e967da0",
// }
//
+ // withdraw
+ //
+ // {
+ // "id":1077391,
+ // "customer_id":1082679,
+ // "amount":"21.9000000000000000",
+ // "txid":"",
+ // "is_internal":false,
+ // "kind":"on_chain",
+ // "state":"PENDING",
+ // "inserted_at":"2020-06-03T00:50:57+00:00",
+ // "updated_at":"2020-06-03T00:50:57+00:00",
+ // "memo":"",
+ // "target_address":"rDYtYT3dBeuw376rvHqoZBKW3UmvguoBAf",
+ // "fee":"0.1000000000000000",
+ // "asset_symbol":"XRP"
+ // }
+ //
const currencyId = this.safeString (transaction, 'asset_symbol');
const code = this.safeCurrencyCode (currencyId);
const id = this.safeInteger (transaction, 'id');
@@ -9135,35 +7701,25 @@ module.exports = class bigone extends Exchange {
// {
// "code":0,
// "message":"",
- // "data":[
- // {
- // "id":1,
- // "customer_id":7,
- // "asset_uuid":"50293b12-5be8-4f5b-b31d-d43cdd5ccc29",
- // "amount":"100",
- // "recipient":null,
- // "state":"PENDING",
- // "is_internal":true,
- // "note":"asdsadsad",
- // "kind":"on_chain",
- // "txid":"asdasdasdsadsadsad",
- // "confirms":5,
- // "inserted_at":null,
- // "updated_at":null,
- // "completed_at":null,
- // "commision":null,
- // "explain":""
- // }
- // ]
+ // "data":{
+ // "id":1077391,
+ // "customer_id":1082679,
+ // "amount":"21.9000000000000000",
+ // "txid":"",
+ // "is_internal":false,
+ // "kind":"on_chain",
+ // "state":"PENDING",
+ // "inserted_at":"2020-06-03T00:50:57+00:00",
+ // "updated_at":"2020-06-03T00:50:57+00:00",
+ // "memo":"",
+ // "target_address":"rDYtYT3dBeuw376rvHqoZBKW3UmvguoBAf",
+ // "fee":"0.1000000000000000",
+ // "asset_symbol":"XRP"
+ // }
// }
//
- const data = this.safeValue (response, 'data', []);
- const dataLength = data.length;
- if (dataLength < 1) {
- throw new ExchangeError (this.id + ' withdraw() returned an empty response');
- }
- const transaction = data[0];
- return this.parseTransaction (transaction, currency);
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTransaction (data, currency);
}
handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
@@ -9186,13 +7742,13 @@ module.exports = class bigone extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],25:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],23:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied, NotSupported } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied, NotSupported, BadRequest, BadSymbol, AccountSuspended, OrderImmediatelyFillable } = require ('./base/errors');
const { ROUND, TRUNCATE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -9208,25 +7764,33 @@ module.exports = class binance extends Exchange {
'pro': true,
// new metainfo interface
'has': {
- 'fetchDepositAddress': true,
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchBidsAsks': true,
- 'fetchTickers': true,
- 'fetchTime': true,
- 'fetchOHLCV': true,
+ 'fetchClosedOrders': 'emulated',
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchFundingFees': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrders': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': 'emulated',
- 'withdraw': true,
- 'fetchFundingFees': true,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
- 'fetchTransactions': false,
+ 'fetchOrderBook': true,
+ 'fetchStatus': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
- 'cancelAllOrders': true,
+ 'fetchTransactions': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1m',
@@ -9248,15 +7812,26 @@ module.exports = class binance extends Exchange {
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/29604020-d5483cdc-87ee-11e7-94c7-d1a8d9169293.jpg',
'test': {
+ 'dapiPublic': 'https://testnet.binancefuture.com/dapi/v1',
+ 'dapiPrivate': 'https://testnet.binancefuture.com/dapi/v1',
'fapiPublic': 'https://testnet.binancefuture.com/fapi/v1',
'fapiPrivate': 'https://testnet.binancefuture.com/fapi/v1',
+ 'fapiPrivateV2': 'https://testnet.binancefuture.com/fapi/v2',
+ 'public': 'https://testnet.binance.vision/api/v3',
+ 'private': 'https://testnet.binance.vision/api/v3',
+ 'v3': 'https://testnet.binance.vision/api/v3',
+ 'v1': 'https://testnet.binance.vision/api/v1',
},
'api': {
- 'web': 'https://www.binance.com',
'wapi': 'https://api.binance.com/wapi/v3',
'sapi': 'https://api.binance.com/sapi/v1',
+ 'dapiPublic': 'https://dapi.binance.com/dapi/v1',
+ 'dapiPrivate': 'https://dapi.binance.com/dapi/v1',
+ 'dapiData': 'https://dapi.binance.com/futures/data',
'fapiPublic': 'https://fapi.binance.com/fapi/v1',
'fapiPrivate': 'https://fapi.binance.com/fapi/v1',
+ 'fapiData': 'https://fapi.binance.com/futures/data',
+ 'fapiPrivateV2': 'https://fapi.binance.com/fapi/v2',
'public': 'https://api.binance.com/api/v3',
'private': 'https://api.binance.com/api/v3',
'v3': 'https://api.binance.com/api/v3',
@@ -9271,12 +7846,6 @@ module.exports = class binance extends Exchange {
'fees': 'https://www.binance.com/en/fee/schedule',
},
'api': {
- 'web': {
- 'get': [
- 'exchange/public/product',
- 'assetWithdraw/getAllAsset.html',
- ],
- },
// the API structure below will need 3-layer apidefs
'sapi': {
'get': [
@@ -9301,7 +7870,19 @@ module.exports = class binance extends Exchange {
'margin/myTrades',
'margin/maxBorrowable',
'margin/maxTransferable',
+ 'margin/isolated/transfer',
+ 'margin/isolated/account',
+ 'margin/isolated/pair',
+ 'margin/isolated/allPairs',
'futures/transfer',
+ 'futures/loan/borrow/history',
+ 'futures/loan/repay/history',
+ 'futures/loan/wallet',
+ 'futures/loan/configs',
+ 'futures/loan/calcAdjustLevel',
+ 'futures/loan/calcMaxAdjustAmount',
+ 'futures/loan/adjustCollateral/history',
+ 'futures/loan/liquidationHistory',
// https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi
'capital/config/getall', // get networks for withdrawing USDT ERC20 vs USDT Omni
'capital/deposit/address',
@@ -9312,9 +7893,12 @@ module.exports = class binance extends Exchange {
'sub-account/futures/account',
'sub-account/futures/accountSummary',
'sub-account/futures/positionRisk',
+ 'sub-account/futures/internalTransfer',
'sub-account/margin/account',
'sub-account/margin/accountSummary',
+ 'sub-account/spotSummary',
'sub-account/status',
+ 'sub-account/transfer/subUserHistory',
// lending endpoints
'lending/daily/product/list',
'lending/daily/userLeftQuota',
@@ -9326,6 +7910,20 @@ module.exports = class binance extends Exchange {
'lending/union/interestHistory',
'lending/project/list',
'lending/project/position/list',
+ // mining endpoints
+ 'mining/pub/algoList',
+ 'mining/pub/coinList',
+ 'mining/worker/detail',
+ 'mining/worker/list',
+ 'mining/payment/list',
+ 'mining/statistics/user/status',
+ 'mining/statistics/user/list',
+ // liquid swap endpoints
+ 'bswap/pools',
+ 'bswap/liquidity',
+ 'bswap/liquidityOps',
+ 'bswap/quote',
+ 'bswap/swap',
],
'post': [
'asset/dust',
@@ -9336,22 +7934,39 @@ module.exports = class binance extends Exchange {
'margin/loan',
'margin/repay',
'margin/order',
+ 'margin/isolated/create',
+ 'margin/isolated/transfer',
+ 'sub-account/margin/transfer',
'sub-account/margin/enable',
'sub-account/margin/enable',
'sub-account/futures/enable',
+ 'sub-account/futures/transfer',
+ 'sub-account/futures/internalTransfer',
+ 'sub-account/transfer/subToSub',
+ 'sub-account/transfer/subToMaster',
'userDataStream',
+ 'userDataStream/isolated',
'futures/transfer',
+ 'futures/loan/borrow',
+ 'futures/loan/repay',
+ 'futures/loan/adjustCollateral',
// lending
'lending/customizedFixed/purchase',
'lending/daily/purchase',
'lending/daily/redeem',
+ // liquid swap endpoints
+ 'bswap/liquidityAdd',
+ 'bswap/liquidityRemove',
+ 'bswap/swap',
],
'put': [
'userDataStream',
+ 'userDataStream/isolated',
],
'delete': [
'margin/order',
'userDataStream',
+ 'userDataStream/isolated',
],
},
'wapi': {
@@ -9374,6 +7989,75 @@ module.exports = class binance extends Exchange {
'sub-account/assets',
],
},
+ 'dapiPublic': {
+ 'get': [
+ 'ping',
+ 'time',
+ 'exchangeInfo',
+ 'depth',
+ 'trades',
+ 'historicalTrades',
+ 'aggTrades',
+ 'premiumIndex',
+ 'fundingRate',
+ 'klines',
+ 'continuousKlines',
+ 'indexPriceKlines',
+ 'markPriceKlines',
+ 'ticker/24hr',
+ 'ticker/price',
+ 'ticker/bookTicker',
+ 'allForceOrders',
+ 'openInterest',
+ ],
+ },
+ 'dapiData': {
+ 'get': [
+ 'openInterestHist',
+ 'topLongShortAccountRatio',
+ 'topLongShortPositionRatio',
+ 'globalLongShortAccountRatio',
+ 'takerBuySellVol',
+ 'basis',
+ ],
+ },
+ 'dapiPrivate': {
+ 'get': [
+ 'positionSide/dual',
+ 'order',
+ 'openOrder',
+ 'openOrders',
+ 'allOrders',
+ 'balance',
+ 'account',
+ 'positionMargin/history',
+ 'positionRisk',
+ 'userTrades',
+ 'income',
+ 'leverageBracket',
+ 'forceOrders',
+ 'adlQuantile',
+ ],
+ 'post': [
+ 'positionSide/dual',
+ 'order',
+ 'batchOrders',
+ 'countdownCancelAll',
+ 'leverage',
+ 'marginType',
+ 'positionMargin',
+ 'listenKey',
+ ],
+ 'put': [
+ 'listenKey',
+ ],
+ 'delete': [
+ 'order',
+ 'allOpenOrders',
+ 'batchOrders',
+ 'listenKey',
+ ],
+ },
'fapiPublic': {
'get': [
'ping',
@@ -9391,19 +8075,31 @@ module.exports = class binance extends Exchange {
'ticker/bookTicker',
'allForceOrders',
'openInterest',
- 'leverageBracket',
+ 'indexInfo',
+ ],
+ },
+ 'fapiData': {
+ 'get': [
+ 'openInterestHist',
+ 'topLongShortAccountRatio',
+ 'topLongShortPositionRatio',
+ 'globalLongShortAccountRatio',
+ 'takerlongshortRatio',
],
},
'fapiPrivate': {
'get': [
+ 'allForceOrders',
'allOrders',
'openOrder',
'openOrders',
'order',
'account',
'balance',
+ 'leverageBracket',
'positionMargin/history',
'positionRisk',
+ 'positionSide/dual',
'userTrades',
'income',
],
@@ -9415,6 +8111,7 @@ module.exports = class binance extends Exchange {
'order',
'leverage',
'listenKey',
+ 'countdownCancelAll',
],
'put': [
'listenKey',
@@ -9426,6 +8123,13 @@ module.exports = class binance extends Exchange {
'listenKey',
],
},
+ 'fapiPrivateV2': {
+ 'get': [
+ 'account',
+ 'balance',
+ 'positionRisk',
+ ],
+ },
'v3': {
'get': [
'ticker/price',
@@ -9487,10 +8191,9 @@ module.exports = class binance extends Exchange {
},
// exchange-specific options
'options': {
- 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades
- 'fetchTickersMethod': 'publicGetTicker24hr',
+ // 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades
'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
- 'defaultType': 'spot', // 'spot', 'future'
+ 'defaultType': 'spot', // 'spot', 'future', 'margin', 'delivery'
'hasAlreadyAuthenticatedSuccessfully': false,
'warnOnFetchOpenOrdersWithoutSymbol': true,
'recvWindow': 5 * 1000, // 5 sec, binance default
@@ -9501,70 +8204,81 @@ module.exports = class binance extends Exchange {
'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'
},
+ 'quoteOrderQty': true, // whether market orders support amounts in quote currency
},
+ // https://binance-docs.github.io/apidocs/spot/en/#error-codes-2
'exceptions': {
'API key does not exist': AuthenticationError,
- 'Order would trigger immediately.': InvalidOrder,
+ 'Order would trigger immediately.': OrderImmediatelyFillable,
+ 'Order would immediately match and take.': OrderImmediatelyFillable, // {"code":-2010,"msg":"Order would immediately match and take."}
'Account has insufficient balance for requested action.': InsufficientFunds,
'Rest API trading is not enabled.': ExchangeNotAvailable,
"You don't have permission.": PermissionDenied, // {"msg":"You don't have permission.","success":false}
'Market is closed.': ExchangeNotAvailable, // {"code":-1013,"msg":"Market is closed."}
+ 'Too many requests.': DDoSProtection, // {"msg":"Too many requests. Please try again later.","success":false}
'-1000': ExchangeNotAvailable, // {"code":-1000,"msg":"An unknown error occured while processing the request."}
+ '-1001': ExchangeNotAvailable, // 'Internal error; unable to process your request. Please try again.'
+ '-1002': AuthenticationError, // 'You are not authorized to execute this request.'
'-1003': RateLimitExceeded, // {"code":-1003,"msg":"Too much request weight used, current limit is 1200 request weight per 1 MINUTE. Please use the websocket for live updates to avoid polling the API."}
'-1013': InvalidOrder, // createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL
+ '-1015': RateLimitExceeded, // 'Too many new orders; current limit is %s orders per %s.'
+ '-1016': ExchangeNotAvailable, // 'This service is no longer available.',
+ '-1020': BadRequest, // 'This operation is not supported.'
'-1021': InvalidNonce, // 'your time is ahead of server'
'-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."}
- '-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
- '-1128': ExchangeError, // {"code":-1128,"msg":"Combination of optional parameters invalid."}
+ '-1100': BadRequest, // createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price'
+ '-1101': BadRequest, // Too many parameters; expected %s and received %s.
+ '-1102': BadRequest, // Param %s or %s must be sent, but both were empty
+ '-1103': BadRequest, // An unknown parameter was sent.
+ '-1104': BadRequest, // Not all sent parameters were read, read 8 parameters but was sent 9
+ '-1105': BadRequest, // Parameter %s was empty.
+ '-1106': BadRequest, // Parameter %s sent when not required.
+ '-1111': BadRequest, // Precision is over the maximum defined for this asset.
+ '-1112': InvalidOrder, // No orders on book for symbol.
+ '-1114': BadRequest, // TimeInForce parameter sent when not required.
+ '-1115': BadRequest, // Invalid timeInForce.
+ '-1116': BadRequest, // Invalid orderType.
+ '-1117': BadRequest, // Invalid side.
+ '-1118': BadRequest, // New client order ID was empty.
+ '-1119': BadRequest, // Original client order ID was empty.
+ '-1120': BadRequest, // Invalid interval.
+ '-1121': BadSymbol, // Invalid symbol.
+ '-1125': AuthenticationError, // This listenKey does not exist.
+ '-1127': BadRequest, // More than %s hours between startTime and endTime.
+ '-1128': BadRequest, // {"code":-1128,"msg":"Combination of optional parameters invalid."}
+ '-1130': BadRequest, // Data sent for paramter %s is not valid.
+ '-1131': BadRequest, // recvWindow must be less than 60000
'-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."
+ '-3005': InsufficientFunds, // {"code":-3005,"msg":"Transferring out not allowed. Transfer out amount exceeds max amount."}
+ '-3008': InsufficientFunds, // {"code":-3008,"msg":"Borrow not allowed. Your borrow amount has exceed maximum borrow amount."}
+ '-3010': ExchangeError, // {"code":-3010,"msg":"Repay not allowed. Repay amount exceeds borrow amount."}
+ '-3022': AccountSuspended, // You account's trading is banned.
},
});
}
- setSandboxMode (enabled) {
- if (enabled) { // eslint-disable-line no-extra-boolean-cast
- if ('test' in this.urls) {
- const type = this.safeString (this.options, 'defaultType', 'spot');
- if (type !== 'future') {
- throw new NotSupported (this.id + ' does not have a sandbox URL for ' + type + " markets, set exchange.options['defaultType'] = 'future' or don't use the sandbox for " + this.id);
- }
- if (typeof this.urls['api'] === 'string') {
- this.urls['api_backup'] = this.urls['api'];
- this.urls['api'] = this.urls['test'];
- } else {
- this.urls['api_backup'] = this.extend ({}, this.urls['api']);
- this.urls['api'] = this.extend ({}, this.urls['test']);
- }
- } else {
- throw new NotSupported (this.id + ' does not have a sandbox URL');
- }
- } else if ('api_backup' in this.urls) {
- if (typeof this.urls['api'] === 'string') {
- this.urls['api'] = this.urls['api_backup'];
- } else {
- this.urls['api'] = this.extend ({}, this.urls['api_backup']);
- }
- }
- }
-
nonce () {
return this.milliseconds () - this.options['timeDifference'];
}
async fetchTime (params = {}) {
const type = this.safeString2 (this.options, 'fetchTime', 'defaultType', 'spot');
- const method = (type === 'spot') ? 'publicGetTime' : 'fapiPublicGetTime';
+ let method = 'publicGetTime';
+ if (type === 'future') {
+ method = 'fapiPublicGetTime';
+ } else if (type === 'delivery') {
+ method = 'dapiPublicGetTime';
+ }
const response = await this[method] (params);
return this.safeInteger (response, 'serverTime');
}
- async loadTimeDifference () {
- const serverTime = await this.fetchTime ();
+ async loadTimeDifference (params = {}) {
+ const serverTime = await this.fetchTime (params);
const after = this.milliseconds ();
this.options['timeDifference'] = after - serverTime;
return this.options['timeDifference'];
@@ -9574,10 +8288,18 @@ module.exports = class binance extends Exchange {
const defaultType = this.safeString2 (this.options, 'fetchMarkets', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
- const method = (type === 'spot') ? 'publicGetExchangeInfo' : 'fapiPublicGetExchangeInfo';
+ if ((type !== 'spot') && (type !== 'future') && (type !== 'margin') && (type !== 'delivery')) {
+ throw new ExchangeError (this.id + " does not support '" + type + "' type, set exchange.options['defaultType'] to 'spot', 'margin', 'delivery' or 'future'"); // eslint-disable-line quotes
+ }
+ let method = 'publicGetExchangeInfo';
+ if (type === 'future') {
+ method = 'fapiPublicGetExchangeInfo';
+ } else if (type === 'delivery') {
+ method = 'dapiPublicGetExchangeInfo';
+ }
const response = await this[method] (query);
//
- // spot
+ // spot / margin
//
// {
// "timezone":"UTC",
@@ -9617,7 +8339,7 @@ module.exports = class binance extends Exchange {
// ],
// }
//
- // futures (fapi)
+ // futures/usdt-margined (fapi)
//
// {
// "timezone":"UTC",
@@ -9652,6 +8374,76 @@ module.exports = class binance extends Exchange {
// ]
// }
//
+ // delivery/coin-margined (dapi)
+ //
+ // {
+ // "timezone": "UTC",
+ // "serverTime": 1597667052958,
+ // "rateLimits": [
+ // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000},
+ // {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":6000}
+ // ],
+ // "exchangeFilters": [],
+ // "symbols": [
+ // {
+ // "symbol": "BTCUSD_200925",
+ // "pair": "BTCUSD",
+ // "contractType": "CURRENT_QUARTER",
+ // "deliveryDate": 1601020800000,
+ // "onboardDate": 1590739200000,
+ // "contractStatus": "TRADING",
+ // "contractSize": 100,
+ // "marginAsset": "BTC",
+ // "maintMarginPercent": "2.5000",
+ // "requiredMarginPercent": "5.0000",
+ // "baseAsset": "BTC",
+ // "quoteAsset": "USD",
+ // "pricePrecision": 1,
+ // "quantityPrecision": 0,
+ // "baseAssetPrecision": 8,
+ // "quotePrecision": 8,
+ // "equalQtyPrecision": 4,
+ // "filters": [
+ // {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"},
+ // {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"},
+ // {"stepSize":"0","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"},
+ // {"limit":200,"filterType":"MAX_NUM_ORDERS"},
+ // {"multiplierDown":"0.9500","multiplierUp":"1.0500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"}
+ // ],
+ // "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"],
+ // "timeInForce": ["GTC","IOC","FOK","GTX"]
+ // },
+ // {
+ // "symbol": "BTCUSD_PERP",
+ // "pair": "BTCUSD",
+ // "contractType": "PERPETUAL",
+ // "deliveryDate": 4133404800000,
+ // "onboardDate": 1596006000000,
+ // "contractStatus": "TRADING",
+ // "contractSize": 100,
+ // "marginAsset": "BTC",
+ // "maintMarginPercent": "2.5000",
+ // "requiredMarginPercent": "5.0000",
+ // "baseAsset": "BTC",
+ // "quoteAsset": "USD",
+ // "pricePrecision": 1,
+ // "quantityPrecision": 0,
+ // "baseAssetPrecision": 8,
+ // "quotePrecision": 8,
+ // "equalQtyPrecision": 4,
+ // "filters": [
+ // {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"},
+ // {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"},
+ // {"stepSize":"1","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"},
+ // {"limit":200,"filterType":"MAX_NUM_ORDERS"},
+ // {"multiplierDown":"0.8500","multiplierUp":"1.1500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"}
+ // ],
+ // "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"],
+ // "timeInForce": ["GTC","IOC","FOK","GTX"]
+ // }
+ // ]
+ // }
+ //
if (this.options['adjustForTimeDifference']) {
await this.loadTimeDifference ();
}
@@ -9659,25 +8451,30 @@ module.exports = class binance extends Exchange {
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
- const future = ('maintMarginPercent' in market);
- const spot = !future;
- const marketType = spot ? 'spot' : 'future';
+ const spot = (type === 'spot');
+ const future = (type === 'future');
+ const delivery = (type === 'delivery');
const id = this.safeString (market, 'symbol');
const lowercaseId = this.safeStringLower (market, 'symbol');
- const baseId = market['baseAsset'];
- const quoteId = market['quoteAsset'];
+ const baseId = this.safeString (market, 'baseAsset');
+ const quoteId = this.safeString (market, 'quoteAsset');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
- const symbol = base + '/' + quote;
- const filters = this.indexBy (market['filters'], 'filterType');
+ const parts = id.split ('_');
+ const lastPart = this.safeString (parts, 1);
+ const idSymbol = (delivery) && (lastPart !== 'PERP');
+ const symbol = idSymbol ? id : (base + '/' + quote);
+ const filters = this.safeValue (market, 'filters', []);
+ const filtersByType = this.indexBy (filters, 'filterType');
const precision = {
- 'base': market['baseAssetPrecision'],
- 'quote': market['quotePrecision'],
- 'amount': market['baseAssetPrecision'],
- 'price': market['quotePrecision'],
+ 'base': this.safeInteger (market, 'baseAssetPrecision'),
+ 'quote': this.safeInteger (market, 'quotePrecision'),
+ 'amount': this.safeInteger (market, 'baseAssetPrecision'),
+ 'price': this.safeInteger (market, 'quotePrecision'),
};
- const status = this.safeString (market, 'status');
+ const status = this.safeString2 (market, 'status', 'contractStatus');
const active = (status === 'TRADING');
+ const margin = this.safeValue (market, 'isMarginTradingAllowed', future || delivery);
const entry = {
'id': id,
'lowercaseId': lowercaseId,
@@ -9687,9 +8484,11 @@ module.exports = class binance extends Exchange {
'baseId': baseId,
'quoteId': quoteId,
'info': market,
- 'type': marketType,
+ 'type': type,
'spot': spot,
+ 'margin': margin,
'future': future,
+ 'delivery': delivery,
'active': active,
'precision': precision,
'limits': {
@@ -9707,8 +8506,8 @@ module.exports = class binance extends Exchange {
},
},
};
- if ('PRICE_FILTER' in filters) {
- const filter = filters['PRICE_FILTER'];
+ if ('PRICE_FILTER' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'PRICE_FILTER', {});
// PRICE_FILTER reports zero values for maxPrice
// since they updated filter types in November 2018
// https://github.com/ccxt/ccxt/issues/4286
@@ -9723,8 +8522,8 @@ module.exports = class binance extends Exchange {
}
entry['precision']['price'] = this.precisionFromString (filter['tickSize']);
}
- if ('LOT_SIZE' in filters) {
- const filter = this.safeValue (filters, 'LOT_SIZE', {});
+ if ('LOT_SIZE' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'LOT_SIZE', {});
const stepSize = this.safeString (filter, 'stepSize');
entry['precision']['amount'] = this.precisionFromString (stepSize);
entry['limits']['amount'] = {
@@ -9732,15 +8531,16 @@ module.exports = class binance extends Exchange {
'max': this.safeFloat (filter, 'maxQty'),
};
}
- if ('MARKET_LOT_SIZE' in filters) {
- const filter = this.safeValue (filters, 'MARKET_LOT_SIZE', {});
+ if ('MARKET_LOT_SIZE' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'MARKET_LOT_SIZE', {});
entry['limits']['market'] = {
'min': this.safeFloat (filter, 'minQty'),
'max': this.safeFloat (filter, 'maxQty'),
};
}
- if ('MIN_NOTIONAL' in filters) {
- entry['limits']['cost']['min'] = this.safeFloat (filters['MIN_NOTIONAL'], 'minNotional');
+ if ('MIN_NOTIONAL' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'MIN_NOTIONAL', {});
+ entry['limits']['cost']['min'] = this.safeFloat (filter, 'minNotional');
}
result.push (entry);
}
@@ -9772,7 +8572,18 @@ module.exports = class binance extends Exchange {
await this.loadMarkets ();
const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
- const method = (type === 'spot') ? 'privateGetAccount' : 'fapiPrivateGetAccount';
+ let method = 'privateGetAccount';
+ if (type === 'future') {
+ const options = this.safeValue (this.options, 'future', {});
+ const fetchBalanceOptions = this.safeValue (options, 'fetchBalance', {});
+ method = this.safeString (fetchBalanceOptions, 'method', 'fapiPrivateV2GetAccount');
+ } else if (type === 'delivery') {
+ const options = this.safeValue (this.options, 'delivery', {});
+ const fetchBalanceOptions = this.safeValue (options, 'fetchBalance', {});
+ method = this.safeString (fetchBalanceOptions, 'method', 'dapiPrivateGetAccount');
+ } else if (type === 'margin') {
+ method = 'sapiGetMarginAccount';
+ }
const query = this.omit (params, 'type');
const response = await this[method] (query);
//
@@ -9793,8 +8604,27 @@ module.exports = class binance extends Exchange {
// ]
// }
//
+ // margin
+ //
+ // {
+ // "borrowEnabled":true,
+ // "marginLevel":"999.00000000",
+ // "totalAssetOfBtc":"0.00000000",
+ // "totalLiabilityOfBtc":"0.00000000",
+ // "totalNetAssetOfBtc":"0.00000000",
+ // "tradeEnabled":true,
+ // "transferEnabled":true,
+ // "userAssets":[
+ // {"asset":"MATIC","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"},
+ // {"asset":"VET","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"},
+ // {"asset":"USDT","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"}
+ // ],
+ // }
+ //
// futures (fapi)
//
+ // fapiPrivateGetAccount
+ //
// {
// "feeTier":0,
// "canTrade":true,
@@ -9834,9 +8664,75 @@ module.exports = class binance extends Exchange {
// ]
// }
//
+ // fapiPrivateV2GetAccount
+ //
+ // {
+ // "feeTier":0,
+ // "canTrade":true,
+ // "canDeposit":true,
+ // "canWithdraw":true,
+ // "updateTime":0,
+ // "totalInitialMargin":"0.00000000",
+ // "totalMaintMargin":"0.00000000",
+ // "totalWalletBalance":"0.00000000",
+ // "totalUnrealizedProfit":"0.00000000",
+ // "totalMarginBalance":"0.00000000",
+ // "totalPositionInitialMargin":"0.00000000",
+ // "totalOpenOrderInitialMargin":"0.00000000",
+ // "totalCrossWalletBalance":"0.00000000",
+ // "totalCrossUnPnl":"0.00000000",
+ // "availableBalance":"0.00000000",
+ // "maxWithdrawAmount":"0.00000000",
+ // "assets":[
+ // {
+ // "asset":"BNB",
+ // "walletBalance":"0.01000000",
+ // "unrealizedProfit":"0.00000000",
+ // "marginBalance":"0.01000000",
+ // "maintMargin":"0.00000000",
+ // "initialMargin":"0.00000000",
+ // "positionInitialMargin":"0.00000000",
+ // "openOrderInitialMargin":"0.00000000",
+ // "maxWithdrawAmount":"0.01000000",
+ // "crossWalletBalance":"0.01000000",
+ // "crossUnPnl":"0.00000000",
+ // "availableBalance":"0.01000000"
+ // }
+ // ],
+ // "positions":[
+ // {
+ // "symbol":"BTCUSDT",
+ // "initialMargin":"0",
+ // "maintMargin":"0",
+ // "unrealizedProfit":"0.00000000",
+ // "positionInitialMargin":"0",
+ // "openOrderInitialMargin":"0",
+ // "leverage":"20",
+ // "isolated":false,
+ // "entryPrice":"0.00000",
+ // "maxNotional":"5000000",
+ // "positionSide":"BOTH"
+ // },
+ // ]
+ // }
+ //
+ // fapiPrivateV2GetBalance
+ //
+ // [
+ // {
+ // "accountAlias":"FzFzXquXXqoC",
+ // "asset":"BNB",
+ // "balance":"0.01000000",
+ // "crossWalletBalance":"0.01000000",
+ // "crossUnPnl":"0.00000000",
+ // "availableBalance":"0.01000000",
+ // "maxWithdrawAmount":"0.01000000"
+ // }
+ // ]
+ //
const result = { 'info': response };
- if (type === 'spot') {
- const balances = this.safeValue (response, 'balances', []);
+ if ((type === 'spot') || (type === 'margin')) {
+ const balances = this.safeValue2 (response, 'balances', 'userAssets', []);
for (let i = 0; i < balances.length; i++) {
const balance = balances[i];
const currencyId = this.safeString (balance, 'asset');
@@ -9847,14 +8743,18 @@ module.exports = class binance extends Exchange {
result[code] = account;
}
} else {
- const balances = this.safeValue (response, 'assets', []);
+ let balances = response;
+ if (!Array.isArray (response)) {
+ balances = this.safeValue (response, 'assets', []);
+ }
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.safeFloat (balance, 'availableBalance');
account['used'] = this.safeFloat (balance, 'initialMargin');
- account['total'] = this.safeFloat (balance, 'marginBalance');
+ account['total'] = this.safeFloat2 (balance, 'marginBalance', 'balance');
result[code] = account;
}
}
@@ -9870,7 +8770,12 @@ module.exports = class binance extends Exchange {
if (limit !== undefined) {
request['limit'] = limit; // default 100, max 5000, see https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#order-book
}
- const method = market['spot'] ? 'publicGetDepth' : 'fapiPublicGetDepth';
+ let method = 'publicGetDepth';
+ if (market['future']) {
+ method = 'fapiPublicGetDepth';
+ } else if (market['delivery']) {
+ method = 'dapiPublicGetDepth';
+ }
const response = await this[method] (this.extend (request, params));
const orderbook = this.parseOrderBook (response);
orderbook['nonce'] = this.safeInteger (response, 'lastUpdateId');
@@ -9878,15 +8783,34 @@ module.exports = class binance extends Exchange {
}
parseTicker (ticker, market = undefined) {
+ //
+ // {
+ // symbol: 'ETHBTC',
+ // priceChange: '0.00068700',
+ // priceChangePercent: '2.075',
+ // weightedAvgPrice: '0.03342681',
+ // prevClosePrice: '0.03310300',
+ // lastPrice: '0.03378900',
+ // lastQty: '0.07700000',
+ // bidPrice: '0.03378900',
+ // bidQty: '7.16800000',
+ // askPrice: '0.03379000',
+ // askQty: '24.00000000',
+ // openPrice: '0.03310200',
+ // highPrice: '0.03388900',
+ // lowPrice: '0.03306900',
+ // volume: '205478.41000000',
+ // quoteVolume: '6868.48826294',
+ // openTime: 1601469986932,
+ // closeTime: 1601556386932,
+ // firstId: 196098772,
+ // lastId: 196186315,
+ // count: 87544
+ // }
+ //
const timestamp = this.safeInteger (ticker, 'closeTime');
- let symbol = undefined;
const marketId = this.safeString (ticker, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const last = this.safeFloat (ticker, 'lastPrice');
return {
'symbol': symbol,
@@ -9931,8 +8855,17 @@ module.exports = class binance extends Exchange {
const request = {
'symbol': market['id'],
};
- const method = market['spot'] ? 'publicGetTicker24hr' : 'fapiPublicGetTicker24hr';
+ let method = 'publicGetTicker24hr';
+ if (market['future']) {
+ method = 'fapiPublicGetTicker24hr';
+ } else if (market['delivery']) {
+ method = 'dapiPublicGetTicker24hr';
+ }
const response = await this[method] (this.extend (request, params));
+ if (Array.isArray (response)) {
+ const firstTicker = this.safeValue (response, 0, {});
+ return this.parseTicker (firstTicker, market);
+ }
return this.parseTicker (response, market);
}
@@ -9949,19 +8882,53 @@ module.exports = class binance extends Exchange {
const defaultType = this.safeString2 (this.options, 'fetchBidsAsks', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
- const method = (type === 'spot') ? 'publicGetTickerBookTicker' : 'fapiPublicGetTickerBookTicker';
+ let method = undefined;
+ if (type === 'future') {
+ method = 'fapiPublicGetTickerBookTicker';
+ } else if (type === 'delivery') {
+ method = 'dapiPublicGetTickerBookTicker';
+ } else {
+ method = 'publicGetTickerBookTicker';
+ }
const response = await this[method] (query);
return this.parseTickers (response, symbols);
}
async fetchTickers (symbols = undefined, params = {}) {
await this.loadMarkets ();
- const method = this.options['fetchTickersMethod'];
- const response = await this[method] (params);
+ const defaultType = this.safeString2 (this.options, 'fetchTickers', 'defaultType', 'spot');
+ const type = this.safeString (params, 'type', defaultType);
+ const query = this.omit (params, 'type');
+ let defaultMethod = undefined;
+ if (type === 'future') {
+ defaultMethod = 'fapiPublicGetTicker24hr';
+ } else if (type === 'delivery') {
+ defaultMethod = 'dapiPublicGetTicker24hr';
+ } else {
+ defaultMethod = 'publicGetTicker24hr';
+ }
+ const method = this.safeString (this.options, 'fetchTickersMethod', defaultMethod);
+ const response = await this[method] (query);
return this.parseTickers (response, symbols);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591478520000,
+ // "0.02501300",
+ // "0.02501800",
+ // "0.02500000",
+ // "0.02500000",
+ // "22.19000000",
+ // 1591478579999,
+ // "0.55490906",
+ // 40,
+ // "10.92900000",
+ // "0.27336462",
+ // "0"
+ // ]
+ //
return [
this.safeInteger (ohlcv, 0),
this.safeFloat (ohlcv, 1),
@@ -9985,8 +8952,20 @@ module.exports = class binance extends Exchange {
if (limit !== undefined) {
request['limit'] = limit; // default == max == 500
}
- const method = market['spot'] ? 'publicGetKlines' : 'fapiPublicGetKlines';
+ let method = 'publicGetKlines';
+ if (market['future']) {
+ method = 'fapiPublicGetKlines';
+ } else if (market['delivery']) {
+ method = 'dapiPublicGetKlines';
+ }
const response = await this[method] (this.extend (request, params));
+ //
+ // [
+ // [1591478520000,"0.02501300","0.02501800","0.02500000","0.02500000","22.19000000",1591478579999,"0.55490906",40,"10.92900000","0.27336462","0"],
+ // [1591478580000,"0.02499600","0.02500900","0.02499400","0.02500300","21.34700000",1591478639999,"0.53370468",24,"7.53800000","0.18850725","0"],
+ // [1591478640000,"0.02500800","0.02501100","0.02500300","0.02500800","154.14200000",1591478699999,"3.85405839",97,"5.32300000","0.13312641","0"],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -10088,14 +9067,8 @@ module.exports = class binance extends Exchange {
if ('isMaker' in trade) {
takerOrMaker = trade['isMaker'] ? 'maker' : 'taker';
}
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (trade, 'symbol');
- market = this.safeValue (this.markets_by_id, marketId);
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (trade, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
let cost = undefined;
if ((price !== undefined) && (amount !== undefined)) {
cost = price * amount;
@@ -10130,7 +9103,14 @@ module.exports = class binance extends Exchange {
const defaultType = this.safeString2 (this.options, 'fetchTrades', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
- const defaultMethod = (type === 'future') ? 'fapiPublicGetTrades' : 'publicGetTrades';
+ let defaultMethod = undefined;
+ if (type === 'future') {
+ defaultMethod = 'fapiPublicGetAggTrades';
+ } else if (type === 'delivery') {
+ defaultMethod = 'dapiPublicGetAggTrades';
+ } else {
+ defaultMethod = 'publicGetAggTrades';
+ }
let method = this.safeString (this.options, 'fetchTradesMethod', defaultMethod);
if (method === 'publicGetAggTrades') {
if (since !== undefined) {
@@ -10141,9 +9121,15 @@ module.exports = class binance extends Exchange {
}
if (type === 'future') {
method = 'fapiPublicGetAggTrades';
+ } else if (type === 'delivery') {
+ method = 'dapiPublicGetAggTrades';
+ }
+ } else if (method === 'publicGetHistoricalTrades') {
+ if (type === 'future') {
+ method = 'fapiPublicGetHistoricalTrades';
+ } else if (type === 'delivery') {
+ method = 'dapiPublicGetHistoricalTrades';
}
- } else if ((method === 'publicGetHistoricalTrades') && (type === 'future')) {
- method = 'fapiPublicGetHistoricalTrades';
}
if (limit !== undefined) {
request['limit'] = limit; // default = 500, maximum = 1000
@@ -10245,14 +9231,8 @@ module.exports = class binance extends Exchange {
// }
//
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
let timestamp = undefined;
if ('time' in order) {
timestamp = this.safeInteger (order, 'time');
@@ -10329,6 +9309,7 @@ module.exports = class binance extends Exchange {
}
}
const clientOrderId = this.safeString (order, 'clientOrderId');
+ const timeInForce = this.safeString (order, 'timeInForce');
return {
'info': order,
'id': id,
@@ -10338,6 +9319,7 @@ module.exports = class binance extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
'amount': amount,
@@ -10354,14 +9336,25 @@ module.exports = class binance extends Exchange {
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
+ const defaultType = this.safeString2 (this.options, 'createOrder', 'defaultType', market['type']);
+ const orderType = this.safeString (params, 'type', defaultType);
+ const clientOrderId = this.safeString2 (params, 'newClientOrderId', 'clientOrderId');
+ params = this.omit (params, [ 'type', 'newClientOrderId', 'clientOrderId' ]);
+ let method = 'privatePostOrder';
+ if (orderType === 'future') {
+ method = 'fapiPrivatePostOrder';
+ } else if (orderType === 'delivery') {
+ method = 'dapiPrivatePostOrder';
+ } else if (orderType === 'margin') {
+ method = 'sapiPostMarginOrder';
+ }
// the next 5 lines are added to support for testing orders
- let method = market['spot'] ? 'privatePostOrder' : 'fapiPrivatePostOrder';
if (market['spot']) {
const test = this.safeValue (params, 'test', false);
if (test) {
method += 'Test';
- params = this.omit (params, 'test');
}
+ params = this.omit (params, 'test');
}
const uppercaseType = type.toUpperCase ();
const validOrderTypes = this.safeValue (market['info'], 'orderTypes');
@@ -10373,45 +9366,90 @@ module.exports = class binance extends Exchange {
'type': uppercaseType,
'side': side.toUpperCase (),
};
- if (uppercaseType === 'MARKET') {
- const quoteOrderQty = this.safeFloat (params, 'quoteOrderQty');
- const precision = market['precision']['price'];
- if (quoteOrderQty !== undefined) {
- request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQty, TRUNCATE, precision, this.precisionMode);
- params = this.omit (params, 'quoteOrderQty');
- } else if (price !== undefined) {
- request['quoteOrderQty'] = this.decimalToPrecision (amount * price, TRUNCATE, precision, this.precisionMode);
- } else {
- request['quantity'] = this.amountToPrecision (symbol, amount);
- }
- } else {
- request['quantity'] = this.amountToPrecision (symbol, amount);
+ if (clientOrderId !== undefined) {
+ request['newClientOrderId'] = clientOrderId;
}
if (market['spot']) {
request['newOrderRespType'] = this.safeValue (this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
}
+ // additional required fields depending on the order type
let timeInForceIsRequired = false;
let priceIsRequired = false;
let stopPriceIsRequired = false;
- if (uppercaseType === 'LIMIT') {
+ let quantityIsRequired = false;
+ //
+ // spot/margin
+ //
+ // LIMIT timeInForce, quantity, price
+ // MARKET quantity or quoteOrderQty
+ // STOP_LOSS quantity, stopPrice
+ // STOP_LOSS_LIMIT timeInForce, quantity, price, stopPrice
+ // TAKE_PROFIT quantity, stopPrice
+ // TAKE_PROFIT_LIMIT timeInForce, quantity, price, stopPrice
+ // LIMIT_MAKER quantity, price
+ //
+ // futures
+ //
+ // LIMIT timeInForce, quantity, price
+ // MARKET quantity
+ // STOP/TAKE_PROFIT quantity, price, stopPrice
+ // STOP_MARKET stopPrice
+ // TAKE_PROFIT_MARKET stopPrice
+ // TRAILING_STOP_MARKET callbackRate
+ //
+ if (uppercaseType === 'MARKET') {
+ const quoteOrderQty = this.safeValue (this.options, 'quoteOrderQty', false);
+ if (quoteOrderQty) {
+ const quoteOrderQty = this.safeFloat (params, 'quoteOrderQty');
+ const precision = market['precision']['price'];
+ if (quoteOrderQty !== undefined) {
+ request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQty, TRUNCATE, precision, this.precisionMode);
+ params = this.omit (params, 'quoteOrderQty');
+ } else if (price !== undefined) {
+ request['quoteOrderQty'] = this.decimalToPrecision (amount * price, TRUNCATE, precision, this.precisionMode);
+ } else {
+ quantityIsRequired = true;
+ }
+ } else {
+ quantityIsRequired = true;
+ }
+ } else if (uppercaseType === 'LIMIT') {
priceIsRequired = true;
timeInForceIsRequired = true;
+ quantityIsRequired = true;
} else if ((uppercaseType === 'STOP_LOSS') || (uppercaseType === 'TAKE_PROFIT')) {
stopPriceIsRequired = true;
+ quantityIsRequired = true;
if (market['future']) {
priceIsRequired = true;
}
} else if ((uppercaseType === 'STOP_LOSS_LIMIT') || (uppercaseType === 'TAKE_PROFIT_LIMIT')) {
+ quantityIsRequired = true;
stopPriceIsRequired = true;
priceIsRequired = true;
timeInForceIsRequired = true;
} else if (uppercaseType === 'LIMIT_MAKER') {
priceIsRequired = true;
+ quantityIsRequired = true;
} else if (uppercaseType === 'STOP') {
+ quantityIsRequired = true;
stopPriceIsRequired = true;
priceIsRequired = true;
- } else if (uppercaseType === 'STOP_MARKET') {
+ } else if ((uppercaseType === 'STOP_MARKET') || (uppercaseType === 'TAKE_PROFIT_MARKET')) {
+ const closePosition = this.safeValue (params, 'closePosition');
+ if (closePosition === undefined) {
+ quantityIsRequired = true;
+ }
stopPriceIsRequired = true;
+ } else if (uppercaseType === 'TRAILING_STOP_MARKET') {
+ quantityIsRequired = true;
+ const callbackRate = this.safeFloat (params, 'callbackRate');
+ if (callbackRate === undefined) {
+ throw new InvalidOrder (this.id + ' createOrder method requires a callbackRate extra param for a ' + type + ' order');
+ }
+ }
+ if (quantityIsRequired) {
+ request['quantity'] = this.amountToPrecision (symbol, amount);
}
if (priceIsRequired) {
if (price === undefined) {
@@ -10441,17 +9479,27 @@ module.exports = class binance extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
- const method = market['spot'] ? 'privateGetOrder' : 'fapiPrivateGetOrder';
+ const defaultType = this.safeString2 (this.options, 'fetchOrder', 'defaultType', market['type']);
+ const type = this.safeString (params, 'type', defaultType);
+ let method = 'privateGetOrder';
+ if (type === 'future') {
+ method = 'fapiPrivateGetOrder';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateGetOrder';
+ } else if (type === 'margin') {
+ method = 'sapiGetMarginOrder';
+ }
const request = {
'symbol': market['id'],
};
- const origClientOrderId = this.safeValue (params, 'origClientOrderId');
- if (origClientOrderId !== undefined) {
- request['origClientOrderId'] = origClientOrderId;
+ const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['origClientOrderId'] = clientOrderId;
} else {
request['orderId'] = parseInt (id);
}
- const response = await this[method] (this.extend (request, params));
+ const query = this.omit (params, [ 'type', 'clientOrderId', 'origClientOrderId' ]);
+ const response = await this[method] (this.extend (request, query));
return this.parseOrder (response, market);
}
@@ -10461,6 +9509,16 @@ module.exports = class binance extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
+ const defaultType = this.safeString2 (this.options, 'fetchOrders', 'defaultType', market['type']);
+ const type = this.safeString (params, 'type', defaultType);
+ let method = 'privateGetAllOrders';
+ if (type === 'future') {
+ method = 'fapiPrivateGetAllOrders';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateGetAllOrders';
+ } else if (type === 'margin') {
+ method = 'sapiGetMarginAllOrders';
+ }
const request = {
'symbol': market['id'],
};
@@ -10470,10 +9528,11 @@ module.exports = class binance extends Exchange {
if (limit !== undefined) {
request['limit'] = limit;
}
- const method = market['spot'] ? 'privateGetAllOrders' : 'fapiPrivateGetAllOrders';
- const response = await this[method] (this.extend (request, params));
+ const query = this.omit (params, 'type');
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
//
- // Spot:
// [
// {
// "symbol": "LTCBTC",
@@ -10495,7 +9554,8 @@ module.exports = class binance extends Exchange {
// }
// ]
//
- // Futures:
+ // futures
+ //
// [
// {
// "symbol": "BTCUSDT",
@@ -10526,8 +9586,9 @@ module.exports = class binance extends Exchange {
if (symbol !== undefined) {
market = this.market (symbol);
request['symbol'] = market['id'];
- type = market['type'];
- query = params;
+ const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', market['type']);
+ type = this.safeString (params, 'type', defaultType);
+ query = this.omit (params, 'type');
} else if (this.options['warnOnFetchOpenOrdersWithoutSymbol']) {
const symbols = this.symbols;
const numSymbols = symbols.length;
@@ -10538,7 +9599,14 @@ module.exports = class binance extends Exchange {
type = this.safeString (params, 'type', defaultType);
query = this.omit (params, 'type');
}
- const method = (type === 'spot') ? 'privateGetOpenOrders' : 'fapiPrivateGetOpenOrders';
+ let method = 'privateGetOpenOrders';
+ if (type === 'future') {
+ method = 'fapiPrivateGetOpenOrders';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateGetOpenOrders';
+ } else if (type === 'margin') {
+ method = 'sapiGetMarginOpenOrders';
+ }
const response = await this[method] (this.extend (request, query));
return this.parseOrders (response, market, since, limit);
}
@@ -10554,8 +9622,10 @@ module.exports = class binance extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
+ const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', market['type']);
+ const type = this.safeString (params, 'type', defaultType);
// https://github.com/ccxt/ccxt/issues/6507
- const origClientOrderId = this.safeValue (params, 'origClientOrderId');
+ const origClientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId');
const request = {
'symbol': market['id'],
// 'orderId': parseInt (id),
@@ -10566,8 +9636,16 @@ module.exports = class binance extends Exchange {
} else {
request['origClientOrderId'] = origClientOrderId;
}
- const method = market['spot'] ? 'privateDeleteOrder' : 'fapiPrivateDeleteOrder';
- const response = await this[method] (this.extend (request, params));
+ let method = 'privateDeleteOrder';
+ if (type === 'future') {
+ method = 'fapiPrivateDeleteOrder';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateDeleteOrder';
+ } else if (type === 'margin') {
+ method = 'sapiDeleteMarginOrder';
+ }
+ const query = this.omit (params, [ 'type', 'origClientOrderId', 'clientOrderId' ]);
+ const response = await this[method] (this.extend (request, query));
return this.parseOrder (response);
}
@@ -10583,7 +9661,12 @@ module.exports = class binance extends Exchange {
const defaultType = this.safeString2 (this.options, 'cancelAllOrders', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
- const method = (type === 'spot') ? 'privateDeleteOpenOrders' : 'fapiPrivateDeleteAllOpenOrders';
+ let method = 'privateDeleteOpenOrders';
+ if (type === 'future') {
+ method = 'fapiPrivateDeleteAllOpenOrders';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateDeleteAllOpenOrders';
+ }
const response = await this[method] (this.extend (request, query));
if (Array.isArray (response)) {
return this.parseOrders (response, market);
@@ -10592,13 +9675,73 @@ module.exports = class binance extends Exchange {
}
}
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.fetchBalance (params);
+ const info = this.safeValue (response, 'info', {});
+ //
+ // futures, delivery
+ //
+ // {
+ // "feeTier":0,
+ // "canTrade":true,
+ // "canDeposit":true,
+ // "canWithdraw":true,
+ // "updateTime":0,
+ // "assets":[
+ // {
+ // "asset":"ETH",
+ // "walletBalance":"0.09886711",
+ // "unrealizedProfit":"0.00000000",
+ // "marginBalance":"0.09886711",
+ // "maintMargin":"0.00000000",
+ // "initialMargin":"0.00000000",
+ // "positionInitialMargin":"0.00000000",
+ // "openOrderInitialMargin":"0.00000000",
+ // "maxWithdrawAmount":"0.09886711",
+ // "crossWalletBalance":"0.09886711",
+ // "crossUnPnl":"0.00000000",
+ // "availableBalance":"0.09886711"
+ // }
+ // ],
+ // "positions":[
+ // {
+ // "symbol":"BTCUSD_201225",
+ // "initialMargin":"0",
+ // "maintMargin":"0",
+ // "unrealizedProfit":"0.00000000",
+ // "positionInitialMargin":"0",
+ // "openOrderInitialMargin":"0",
+ // "leverage":"20",
+ // "isolated":false,
+ // "positionSide":"BOTH",
+ // "entryPrice":"0.00000000",
+ // "maxQty":"250", // "maxNotional" on futures
+ // },
+ // ]
+ // }
+ //
+ const positions = this.safeValue2 (info, 'positions', 'userAssets', []);
+ // todo unify parsePosition/parsePositions
+ return positions;
+ }
+
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
- const method = market['spot'] ? 'privateGetMyTrades' : 'fapiPrivateGetUserTrades';
+ const type = this.safeValue (params, 'type', market['type']);
+ let method = undefined;
+ if (type === 'spot') {
+ method = 'privateGetMyTrades';
+ } else if (type === 'future') {
+ method = 'fapiPrivateGetUserTrades';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateGetUserTrades';
+ }
+ params = this.omit (params, 'type');
const request = {
'symbol': market['id'],
};
@@ -10611,6 +9754,7 @@ module.exports = class binance extends Exchange {
const response = await this[method] (this.extend (request, params));
//
// spot trade
+ //
// [
// {
// "symbol": "BNBBTC",
@@ -10648,6 +9792,7 @@ module.exports = class binance extends Exchange {
// "time": 1569514978020
// }
// ]
+ //
return this.parseTrades (response, market, since, limit);
}
@@ -10903,6 +10048,7 @@ module.exports = class binance extends Exchange {
if (feeCost !== undefined) {
fee = { 'currency': code, 'cost': feeCost };
}
+ const updated = this.safeInteger (transaction, 'successTime');
return {
'info': transaction,
'id': id,
@@ -10910,12 +10056,16 @@ module.exports = class binance extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'address': address,
+ 'addressTo': address,
+ 'addressFrom': undefined,
'tag': tag,
+ 'tagTo': tag,
+ 'tagFrom': undefined,
'type': type,
'amount': amount,
'currency': code,
'status': status,
- 'updated': undefined,
+ 'updated': updated,
'fee': fee,
};
}
@@ -10936,7 +10086,7 @@ module.exports = class binance extends Exchange {
this.checkAddress (address);
return {
'currency': code,
- 'address': this.checkAddress (address),
+ 'address': address,
'tag': tag,
'info': response,
};
@@ -11013,11 +10163,7 @@ module.exports = class binance extends Exchange {
// }
//
const marketId = this.safeString (fee, 'symbol');
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- const market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId);
return {
'info': fee,
'symbol': symbol,
@@ -11076,6 +10222,9 @@ module.exports = class binance extends Exchange {
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ if (!(api in this.urls['api'])) {
+ throw new NotSupported (this.id + ' does not have a testnet/sandbox URL for ' + api + ' endpoints');
+ }
let url = this.urls['api'][api];
url += '/' + path;
if (api === 'wapi') {
@@ -11102,23 +10251,24 @@ module.exports = class binance extends Exchange {
throw new AuthenticationError (this.id + ' userDataStream endpoint requires `apiKey` credential');
}
}
- if ((api === 'private') || (api === 'sapi') || (api === 'wapi' && path !== 'systemStatus') || (api === 'fapiPrivate')) {
+ if ((api === 'private') || (api === 'sapi') || (api === 'wapi' && path !== 'systemStatus') || (api === 'dapiPrivate') || (api === 'fapiPrivate') || (api === 'fapiPrivateV2')) {
this.checkRequiredCredentials ();
let query = undefined;
+ const recvWindow = this.safeInteger (this.options, 'recvWindow', 5000);
if ((api === 'sapi') && (path === 'asset/dust')) {
query = this.urlencodeWithArrayRepeat (this.extend ({
'timestamp': this.nonce (),
- 'recvWindow': this.options['recvWindow'],
+ 'recvWindow': recvWindow,
}, params));
} else if (path === 'batchOrders') {
query = this.rawencode (this.extend ({
'timestamp': this.nonce (),
- 'recvWindow': this.options['recvWindow'],
+ 'recvWindow': recvWindow,
}, params));
} else {
query = this.urlencode (this.extend ({
'timestamp': this.nonce (),
- 'recvWindow': this.options['recvWindow'],
+ 'recvWindow': recvWindow,
}, params));
}
const signature = this.hmac (this.encode (query), this.encode (this.secret));
@@ -11163,52 +10313,52 @@ module.exports = class binance extends Exchange {
throw new InvalidOrder (this.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid float value in general, use this.priceToPrecision (symbol, amount) ' + body);
}
}
- if (body.length > 0) {
- if (body[0] === '{') {
- // check success value for wapi endpoints
- // response in format {'msg': 'The coin does not exist.', 'success': true/false}
- const success = this.safeValue (response, 'success', true);
- if (!success) {
- const message = this.safeString (response, 'msg');
- let parsedMessage = undefined;
- if (message !== undefined) {
- try {
- parsedMessage = JSON.parse (message);
- } catch (e) {
- // do nothing
- parsedMessage = undefined;
- }
- if (parsedMessage !== undefined) {
- response = parsedMessage;
- }
- }
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ // check success value for wapi endpoints
+ // response in format {'msg': 'The coin does not exist.', 'success': true/false}
+ const success = this.safeValue (response, 'success', true);
+ if (!success) {
+ const message = this.safeString (response, 'msg');
+ let parsedMessage = undefined;
+ if (message !== undefined) {
+ try {
+ parsedMessage = JSON.parse (message);
+ } catch (e) {
+ // do nothing
+ parsedMessage = undefined;
}
- const message = this.safeString (response, 'msg');
- if (message !== undefined) {
- this.throwExactlyMatchedException (this.exceptions, message, this.id + ' ' + message);
- }
- // checks against error codes
- const error = this.safeString (response, 'code');
- if (error !== undefined) {
- // https://github.com/ccxt/ccxt/issues/6501
- if (error === '200') {
- return;
- }
- // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
- // despite that their message is very confusing, it is raised by Binance
- // on a temporary ban, the API key is valid, but disabled for a while
- if ((error === '-2015') && this.options['hasAlreadyAuthenticatedSuccessfully']) {
- throw new DDoSProtection (this.id + ' temporary banned: ' + body);
- }
- const feedback = this.id + ' ' + body;
- this.throwExactlyMatchedException (this.exceptions, error, feedback);
- throw new ExchangeError (feedback);
- }
- if (!success) {
- throw new ExchangeError (this.id + ' ' + body);
+ if (parsedMessage !== undefined) {
+ response = parsedMessage;
}
}
}
+ const message = this.safeString (response, 'msg');
+ if (message !== undefined) {
+ this.throwExactlyMatchedException (this.exceptions, message, this.id + ' ' + message);
+ }
+ // checks against error codes
+ const error = this.safeString (response, 'code');
+ if (error !== undefined) {
+ // https://github.com/ccxt/ccxt/issues/6501
+ // https://github.com/ccxt/ccxt/issues/7742
+ if ((error === '200') || (error === '0')) {
+ return;
+ }
+ // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
+ // despite that their message is very confusing, it is raised by Binance
+ // on a temporary ban, the API key is valid, but disabled for a while
+ if ((error === '-2015') && this.options['hasAlreadyAuthenticatedSuccessfully']) {
+ throw new DDoSProtection (this.id + ' temporary banned: ' + body);
+ }
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions, error, feedback);
+ throw new ExchangeError (feedback);
+ }
+ if (!success) {
+ throw new ExchangeError (this.id + ' ' + body);
+ }
}
async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
@@ -11221,62 +10371,7 @@ module.exports = class binance extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],26:[function(require,module,exports){
-'use strict';
-
-// ---------------------------------------------------------------------------
-
-const binance = require ('./binance.js');
-
-// ---------------------------------------------------------------------------
-
-module.exports = class binanceje extends binance {
- describe () {
- return this.deepExtend (super.describe (), {
- 'id': 'binanceje',
- 'name': 'Binance Jersey',
- 'countries': [ 'JE' ], // Jersey
- 'certified': false,
- 'pro': true,
- 'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/54874009-d526eb00-4df3-11e9-928c-ce6a2b914cd1.jpg',
- 'api': {
- 'web': 'https://www.binance.je',
- 'wapi': 'https://api.binance.je/wapi/v3',
- 'public': 'https://api.binance.je/api/v1',
- 'private': 'https://api.binance.je/api/v3',
- 'v3': 'https://api.binance.je/api/v3',
- 'v1': 'https://api.binance.je/api/v1',
- },
- 'www': 'https://www.binance.je',
- 'referral': 'https://www.binance.je/?ref=35047921',
- 'doc': 'https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md',
- 'fees': 'https://www.binance.je/fees.html',
- },
- 'fees': {
- 'trading': {
- 'tierBased': false,
- 'percentage': true,
- 'taker': 0.0005,
- 'maker': 0.0005,
- },
- // should be deleted, these are outdated and inaccurate
- 'funding': {
- 'tierBased': false,
- 'percentage': false,
- 'withdraw': {
- 'BTC': 0.0005,
- 'ETH': 0.01,
- },
- 'deposit': {},
- },
- },
- });
- }
-};
-
-
-},{"./binance.js":25}],27:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],24:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -11316,18 +10411,21 @@ module.exports = class binanceus extends binance {
'maker': 0.001, // 0.1% trading fee, zero fees for all trading pairs before November 1
},
},
+ 'options': {
+ 'quoteOrderQty': false,
+ },
});
}
};
-},{"./binance.js":25}],28:[function(require,module,exports){
+},{"./binance.js":23}],25:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ArgumentsRequired, ExchangeError } = require ('./base/errors');
+const { ArgumentsRequired, ExchangeError, InvalidNonce, AuthenticationError, PermissionDenied } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -11339,9 +10437,15 @@ module.exports = class bit2c extends Exchange {
'countries': [ 'IL' ], // Israel
'rateLimit': 3000,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27766119-3593220e-5ece-11e7-8b3a-5a041f6bcc3f.jpg',
@@ -11404,11 +10508,18 @@ module.exports = class bit2c extends Exchange {
},
},
'options': {
- 'fetchTradesMethod': 'public_get_exchanges_pair_lasttrades',
+ 'fetchTradesMethod': 'public_get_exchanges_pair_trades',
},
'exceptions': {
- // { "error" : "Please provide valid APIkey" }
- // { "error" : "Please provide valid nonce in Request UInt64.TryParse failed for nonce :" }
+ 'exact': {
+ 'Please provide valid APIkey': AuthenticationError, // { "error" : "Please provide valid APIkey" }
+ },
+ 'broad': {
+ // { "error": "Please provide valid nonce in Request Nonce (1598218490) is not bigger than last nonce (1598218490)."}
+ // { "error": "Please provide valid nonce in Request UInt64.TryParse failed for nonce :" }
+ 'Please provide valid nonce': InvalidNonce,
+ 'please approve new terms of use on site': PermissionDenied, // { "error" : "please approve new terms of use on site." }
+ },
},
});
}
@@ -11528,6 +10639,12 @@ module.exports = class bit2c extends Exchange {
const request = {
'pair': market['id'],
};
+ if (since !== undefined) {
+ request['date'] = parseInt (since);
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // max 100000
+ }
const response = await this[method] (this.extend (request, params));
if (typeof response === 'string') {
throw new ExchangeError (response);
@@ -11610,8 +10727,10 @@ module.exports = class bit2c extends Exchange {
'status': status,
'symbol': symbol,
'type': undefined,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': undefined,
'remaining': undefined,
@@ -11735,15 +10854,32 @@ module.exports = class bit2c extends Exchange {
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'key': this.apiKey,
- 'sign': this.decode (signature),
+ 'sign': signature,
};
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
+
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ //
+ // { "error" : "please approve new terms of use on site." }
+ // { "error": "Please provide valid nonce in Request Nonce (1598218490) is not bigger than last nonce (1598218490)."}
+ //
+ const error = this.safeString (response, 'error');
+ if (error !== undefined) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], error, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], error, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
};
-},{"./base/Exchange":7,"./base/errors":9}],29:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],26:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -11761,10 +10897,17 @@ module.exports = class bitbank extends Exchange {
'countries': [ 'JP' ],
'version': 'v1',
'has': {
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchDepositAddress': true,
+ 'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
- 'fetchMyTrades': true,
- 'fetchDepositAddress': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'timeframes': {
@@ -11824,7 +10967,11 @@ module.exports = class bitbank extends Exchange {
'ETH/BTC': { 'id': 'eth_btc', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC', 'baseId': 'eth', 'quoteId': 'btc' },
'LTC/BTC': { 'id': 'ltc_btc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'baseId': 'ltc', 'quoteId': 'btc' },
'XRP/JPY': { 'id': 'xrp_jpy', 'symbol': 'XRP/JPY', 'base': 'XRP', 'quote': 'JPY', 'baseId': 'xrp', 'quoteId': 'jpy' },
+ 'XLM/JPY': { 'id': 'xlm_jpy', 'symbol': 'XLM/JPY', 'base': 'XLM', 'quote': 'JPY', 'baseId': 'xlm', 'quoteId': 'jpy' },
'BTC/JPY': { 'id': 'btc_jpy', 'symbol': 'BTC/JPY', 'base': 'BTC', 'quote': 'JPY', 'baseId': 'btc', 'quoteId': 'jpy' },
+ 'ETH/JPY': { 'id': 'eth_jpy', 'symbol': 'ETH/JPY', 'base': 'ETH', 'quote': 'JPY', 'baseId': 'eth', 'quoteId': 'jpy' },
+ 'LTC/JPY': { 'id': 'ltc_jpy', 'symbol': 'LTC/JPY', 'base': 'LTC', 'quote': 'JPY', 'baseId': 'ltc', 'quoteId': 'jpy' },
+ 'XRP/BTC': { 'id': 'xrp_btc', 'symbol': 'XRP/BTC', 'base': 'XRP', 'quote': 'BTC', 'baseId': 'xrp', 'quoteId': 'btc' },
},
'fees': {
'trading': {
@@ -11905,7 +11052,8 @@ module.exports = class bitbank extends Exchange {
'pair': market['id'],
};
const response = await this.publicGetPairTicker (this.extend (request, params));
- return this.parseTicker (response['data'], market);
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTicker (data, market);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -11972,17 +11120,29 @@ module.exports = class bitbank extends Exchange {
'pair': market['id'],
};
const response = await this.publicGetPairTransactions (this.extend (request, params));
- return this.parseTrades (response['data']['transactions'], market, since, limit);
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'transactions', []);
+ return this.parseTrades (trades, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // "0.02501786",
+ // "0.02501786",
+ // "0.02501786",
+ // "0.02501786",
+ // "0.0000",
+ // 1591488000000
+ // ]
+ //
return [
- ohlcv[5],
- parseFloat (ohlcv[0]),
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
+ this.safeInteger (ohlcv, 5),
+ this.safeFloat (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
];
}
@@ -11998,7 +11158,28 @@ module.exports = class bitbank extends Exchange {
'yyyymmdd': date.join (''),
};
const response = await this.publicGetPairCandlestickCandletypeYyyymmdd (this.extend (request, params));
- const ohlcv = this.safeValue (response['data']['candlestick'][0], 'ohlcv');
+ //
+ // {
+ // "success":1,
+ // "data":{
+ // "candlestick":[
+ // {
+ // "type":"5min",
+ // "ohlcv":[
+ // ["0.02501786","0.02501786","0.02501786","0.02501786","0.0000",1591488000000],
+ // ["0.02501747","0.02501953","0.02501747","0.02501953","0.3017",1591488300000],
+ // ["0.02501762","0.02501762","0.02500392","0.02500392","0.1500",1591488600000],
+ // ]
+ // }
+ // ],
+ // "timestamp":1591508668190
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const candlestick = this.safeValue (data, 'candlestick', []);
+ const first = this.safeValue (candlestick, 0, {});
+ const ohlcv = this.safeValue (first, 'ohlcv', []);
return this.parseOHLCVs (ohlcv, market, timeframe, since, limit);
}
@@ -12006,9 +11187,10 @@ module.exports = class bitbank extends Exchange {
await this.loadMarkets ();
const response = await this.privateGetUserAssets (params);
const result = { 'info': response };
- const balances = response['data']['assets'];
- for (let i = 0; i < balances.length; i++) {
- const balance = balances[i];
+ const data = this.safeValue (response, 'data', {});
+ const assets = this.safeValue (data, 'assets', []);
+ for (let i = 0; i < assets.length; i++) {
+ const balance = assets[i];
const currencyId = this.safeString (balance, 'asset');
const code = this.safeCurrencyCode (currencyId);
const account = {
@@ -12066,8 +11248,10 @@ module.exports = class bitbank extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -12093,10 +11277,8 @@ module.exports = class bitbank extends Exchange {
'type': type,
};
const response = await this.privatePostUserSpotOrder (this.extend (request, params));
- const order = this.parseOrder (response['data'], market);
- const id = order['id'];
- this.orders[id] = order;
- return order;
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -12107,7 +11289,8 @@ module.exports = class bitbank extends Exchange {
'pair': market['id'],
};
const response = await this.privatePostUserSpotCancelOrder (this.extend (request, params));
- return response['data'];
+ const data = this.safeValue (response, 'data');
+ return data;
}
async fetchOrder (id, symbol = undefined, params = {}) {
@@ -12118,7 +11301,8 @@ module.exports = class bitbank extends Exchange {
'pair': market['id'],
};
const response = await this.privateGetUserSpotOrder (this.extend (request, params));
- return this.parseOrder (response['data']);
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -12134,7 +11318,9 @@ module.exports = class bitbank extends Exchange {
request['since'] = parseInt (since / 1000);
}
const response = await this.privateGetUserSpotActiveOrders (this.extend (request, params));
- return this.parseOrders (response['data']['orders'], market, since, limit);
+ const data = this.safeValue (response, 'data', {});
+ const orders = this.safeValue (data, 'orders', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -12154,7 +11340,9 @@ module.exports = class bitbank extends Exchange {
request['since'] = parseInt (since / 1000);
}
const response = await this.privateGetUserSpotTradeHistory (this.extend (request, params));
- return this.parseTrades (response['data']['trades'], market, since, limit);
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'trades', []);
+ return this.parseTrades (trades, market, since, limit);
}
async fetchDepositAddress (code, params = {}) {
@@ -12164,9 +11352,11 @@ module.exports = class bitbank extends Exchange {
'asset': currency['id'],
};
const response = await this.privateGetUserWithdrawalAccount (this.extend (request, params));
+ const data = this.safeValue (response, 'data', {});
// Not sure about this if there could be more than one account...
- const accounts = response['data']['accounts'];
- const address = this.safeString (accounts[0], 'address');
+ const accounts = this.safeValue (data, 'accounts', []);
+ const firstAccount = this.safeValue (accounts, 0, {});
+ const address = this.safeString (firstAccount, 'address');
return {
'currency': currency,
'address': address,
@@ -12186,7 +11376,8 @@ module.exports = class bitbank extends Exchange {
'amount': amount,
};
const response = await this.privatePostUserRequestWithdrawal (this.extend (request, params));
- const txid = this.safeString (response['data'], 'txid');
+ const data = this.safeValue (response, 'data', {});
+ const txid = this.safeString (data, 'txid');
return {
'info': response,
'id': txid,
@@ -12312,13 +11503,13 @@ module.exports = class bitbank extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],30:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],27:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded, OnMaintenance } = require ('./base/errors');
+const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded, OnMaintenance, PermissionDenied } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -12330,11 +11521,19 @@ module.exports = class bitbay extends Exchange {
'countries': [ 'MT', 'EU' ], // Malta
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': true,
- 'withdraw': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
- 'fetchOpenOrders': true,
'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '60',
@@ -12531,6 +11730,11 @@ module.exports = class bitbay extends Exchange {
'OFFER_WOULD_HAVE_BEEN_PARTIALLY_FILLED': OrderImmediatelyFillable,
'ACTION_LIMIT_EXCEEDED': RateLimitExceeded,
'UNDER_MAINTENANCE': OnMaintenance,
+ 'REQUEST_TIMESTAMP_TOO_OLD': InvalidNonce,
+ 'PERMISSIONS_NOT_SUFFICIENT': PermissionDenied,
+ },
+ 'commonCurrencies': {
+ 'GGC': 'Global Game Coin',
},
});
}
@@ -12643,22 +11847,7 @@ module.exports = class bitbay extends Exchange {
// }
//
const marketId = this.safeString (order, 'market');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.safeInteger (order, 'time');
const amount = this.safeFloat (order, 'startAmount');
const remaining = this.safeFloat (order, 'currentAmount');
@@ -12678,8 +11867,10 @@ module.exports = class bitbay extends Exchange {
'status': undefined,
'symbol': symbol,
'type': this.safeString (order, 'mode'),
+ 'timeInForce': undefined,
'side': this.safeStringLower (order, 'offerType'),
'price': this.safeFloat (order, 'rate'),
+ 'stopPrice': undefined,
'amount': amount,
'cost': undefined,
'filled': filled,
@@ -13142,25 +12333,28 @@ module.exports = class bitbay extends Exchange {
return this.safeString (types, type, type);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
- // [
- // '1582399800000',
- // {
- // o: '0.0001428',
- // c: '0.0001428',
- // h: '0.0001428',
- // l: '0.0001428',
- // v: '4',
- // co: '1'
- // }
- // ]
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // '1582399800000',
+ // {
+ // o: '0.0001428',
+ // c: '0.0001428',
+ // h: '0.0001428',
+ // l: '0.0001428',
+ // v: '4',
+ // co: '1'
+ // }
+ // ]
+ //
+ const first = this.safeValue (ohlcv, 1, {});
return [
- parseInt (ohlcv[0]),
- this.safeFloat (ohlcv[1], 'o'),
- this.safeFloat (ohlcv[1], 'h'),
- this.safeFloat (ohlcv[1], 'l'),
- this.safeFloat (ohlcv[1], 'c'),
- this.safeFloat (ohlcv[1], 'v'),
+ this.safeInteger (ohlcv, 0),
+ this.safeFloat (first, 'o'),
+ this.safeFloat (first, 'h'),
+ this.safeFloat (first, 'l'),
+ this.safeFloat (first, 'c'),
+ this.safeFloat (first, 'v'),
];
}
@@ -13187,8 +12381,18 @@ module.exports = class bitbay extends Exchange {
request['to'] = this.sum (request['from'], timerange);
}
const response = await this.v1_01PublicGetTradingCandleHistorySymbolResolution (this.extend (request, params));
- const ohlcvs = this.safeValue (response, 'items', []);
- return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+ //
+ // {
+ // "status":"Ok",
+ // "items":[
+ // ["1591503060000",{"o":"0.02509572","c":"0.02509438","h":"0.02509664","l":"0.02509438","v":"0.02082165","co":"17"}],
+ // ["1591503120000",{"o":"0.02509606","c":"0.02509515","h":"0.02509606","l":"0.02509487","v":"0.04971703","co":"13"}],
+ // ["1591503180000",{"o":"0.02509532","c":"0.02509589","h":"0.02509589","l":"0.02509454","v":"0.01332236","co":"7"}],
+ // ]
+ // }
+ //
+ const items = this.safeValue (response, 'items', []);
+ return this.parseOHLCVs (items, market, timeframe, since, limit);
}
parseTrade (trade, market = undefined) {
@@ -13243,33 +12447,11 @@ module.exports = class bitbay extends Exchange {
}
const feeCost = this.safeFloat (trade, 'commissionValue');
const marketId = this.safeString (trade, 'market');
- let base = undefined;
- let quote = undefined;
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- base = market['base'];
- quote = market['quote'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- base = this.safeCurrencyCode (baseId);
- quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (market !== undefined) {
- if (symbol === undefined) {
- symbol = market['symbol'];
- }
- if (base === undefined) {
- base = market['base'];
- }
- }
+ market = this.safeMarket (marketId, market, '-');
+ const symbol = market['symbol'];
let fee = undefined;
if (feeCost !== undefined) {
- const feeCcy = (side === 'buy') ? base : quote;
+ const feeCcy = (side === 'buy') ? market['base'] : market['quote'];
fee = {
'currency': feeCcy,
'cost': feeCost,
@@ -13313,7 +12495,7 @@ module.exports = class bitbay extends Exchange {
}
const response = await this.v1_01PublicGetTradingTransactionsSymbol (this.extend (request, params));
const items = this.safeValue (response, 'items');
- return this.parseTrades (items, symbol, since, limit);
+ return this.parseTrades (items, market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
@@ -13328,7 +12510,9 @@ module.exports = class bitbay extends Exchange {
};
if (type === 'limit') {
request['rate'] = price;
+ price = parseFloat (price);
}
+ amount = parseFloat (amount);
const response = await this.v1_01PrivatePostTradingOfferSymbol (this.extend (request, params));
//
// unfilled (open order)
@@ -13418,8 +12602,8 @@ module.exports = class bitbay extends Exchange {
'symbol': symbol,
'type': type,
'side': side,
- 'price': parseFloat (price),
- 'amount': parseFloat (amount),
+ 'price': price,
+ 'amount': amount,
'cost': cost,
'filled': filled,
'remaining': remaining,
@@ -13593,14 +12777,50 @@ module.exports = class bitbay extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],31:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],28:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const hitbtc = require ('./hitbtc.js');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class bitcoincom extends hitbtc {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'bitcoincom',
+ 'name': 'bitcoin.com',
+ 'countries': [ 'KN' ],
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/97296144-514fa300-1861-11eb-952b-3d55d492200b.jpg',
+ 'api': {
+ 'public': 'https://api.exchange.bitcoin.com',
+ 'private': 'https://api.exchange.bitcoin.com',
+ },
+ 'www': 'https://exchange.bitcoin.com',
+ 'doc': 'https://api.exchange.bitcoin.com/api/2/explore',
+ 'fees': 'https://exchange.bitcoin.com/fees-and-limits',
+ 'referral': 'https://exchange.bitcoin.com/referral/da948b21d6c92d69',
+ },
+ 'fees': {
+ 'trading': {
+ 'maker': 0.15 / 100,
+ 'taker': 0.2 / 100,
+ },
+ },
+ });
+ }
+};
+
+},{"./hitbtc.js":89}],29:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { NotSupported, RateLimitExceeded, AuthenticationError, PermissionDenied, ArgumentsRequired, ExchangeError, ExchangeNotAvailable, InsufficientFunds, InvalidOrder, OrderNotFound, InvalidNonce } = require ('./base/errors');
-const { SIGNIFICANT_DIGITS } = require ('./base/functions/number');
+const { NotSupported, RateLimitExceeded, AuthenticationError, PermissionDenied, ArgumentsRequired, ExchangeError, ExchangeNotAvailable, InsufficientFunds, InvalidOrder, OrderNotFound, InvalidNonce, BadSymbol } = require ('./base/errors');
+const { SIGNIFICANT_DIGITS, DECIMAL_PLACES, TRUNCATE, ROUND } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -13616,22 +12836,30 @@ module.exports = class bitfinex extends Exchange {
'pro': true,
// new metainfo interface
'has': {
- 'CORS': false,
'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'CORS': false,
'createDepositAddress': true,
+ 'createOrder': true,
'deposit': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
'fetchDepositAddress': true,
- 'fetchTradingFee': true,
- 'fetchTradingFees': true,
+ 'fetchDeposits': false,
'fetchFundingFees': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTradingFee': true,
+ 'fetchTradingFees': true,
'fetchTransactions': true,
- 'fetchDeposits': false,
'fetchWithdrawals': false,
'withdraw': true,
},
@@ -13885,6 +13113,10 @@ module.exports = class bitfinex extends Exchange {
'DAT': 'DATA',
'DSH': 'DASH',
'DRK': 'DRK',
+ // https://github.com/ccxt/ccxt/issues/7399
+ // https://coinmarketcap.com/currencies/pnetwork/
+ // https://en.cryptonomist.ch/blog/eidoo/the-edo-to-pnt-upgrade-what-you-need-to-know-updated/
+ 'EDO': 'PNT',
'GSD': 'GUSD',
'HOT': 'Hydro Protocol',
'IOS': 'IOST',
@@ -13897,10 +13129,12 @@ module.exports = class bitfinex extends Exchange {
'POY': 'POLY',
'QSH': 'QASH',
'QTM': 'QTUM',
+ 'RBT': 'RBTC',
'SEE': 'SEER',
'SNG': 'SNGLS',
'SPK': 'SPANK',
'STJ': 'STORJ',
+ 'TRI': 'TRIO',
'TSD': 'TUSD',
'YYW': 'YOYOW',
'UDC': 'USDC',
@@ -13925,8 +13159,10 @@ module.exports = class bitfinex extends Exchange {
'Nonce is too small.': InvalidNonce,
'No summary found.': ExchangeError, // fetchTradingFees (summary) endpoint can give this vague error message
'Cannot evaluate your available balance, please try again': ExchangeNotAvailable,
+ 'Unknown symbol': BadSymbol,
},
'broad': {
+ 'Invalid X-BFX-SIGNATURE': AuthenticationError,
'This API key does not have permission': PermissionDenied, // authenticated but not authorized
'not enough exchange balance for ': InsufficientFunds, // when buying cost is greater than the available quote currency
'minimum size for ': InvalidOrder, // when amount below limits.amount.min
@@ -13948,9 +13184,11 @@ module.exports = class bitfinex extends Exchange {
// 'BCH': 'bcash', // undocumented
'BCI': 'bci',
'BFT': 'bft',
+ 'BSV': 'bsv',
'BTC': 'bitcoin',
'BTG': 'bgold',
'CFI': 'cfi',
+ 'COMP': 'comp',
'DAI': 'dai',
'DADI': 'dad',
'DASH': 'dash',
@@ -13969,6 +13207,7 @@ module.exports = class bitfinex extends Exchange {
// https://github.com/ccxt/ccxt/issues/5833
'LEO': 'let', // ETH chain
// 'LEO': 'les', // EOS chain
+ 'LINK': 'link',
'LRC': 'lrc',
'LTC': 'litecoin',
'LYM': 'lym',
@@ -13994,6 +13233,7 @@ module.exports = class bitfinex extends Exchange {
'STORJ': 'stj',
'TNB': 'tnb',
'TRX': 'trx',
+ 'TUSD': 'tsd',
'USD': 'wire',
'USDC': 'udc', // https://github.com/ccxt/ccxt/issues/5833
'UTK': 'utk',
@@ -14096,8 +13336,11 @@ module.exports = class bitfinex extends Exchange {
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
const precision = {
- 'price': market['price_precision'],
- 'amount': undefined,
+ 'price': this.safeInteger (market, 'price_precision'),
+ // https://docs.bitfinex.com/docs/introduction#amount-precision
+ // The amount field allows up to 8 decimals.
+ // Anything exceeding this will be rounded to the 8th decimal.
+ 'amount': 8,
};
const limits = {
'amount': {
@@ -14130,7 +13373,19 @@ module.exports = class bitfinex extends Exchange {
}
amountToPrecision (symbol, amount) {
- return this.numberToString (amount);
+ // https://docs.bitfinex.com/docs/introduction#amount-precision
+ // The amount field allows up to 8 decimals.
+ // Anything exceeding this will be rounded to the 8th decimal.
+ return this.decimalToPrecision (amount, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES);
+ }
+
+ priceToPrecision (symbol, price) {
+ price = this.decimalToPrecision (price, ROUND, this.markets[symbol]['precision']['price'], this.precisionMode);
+ // https://docs.bitfinex.com/docs/introduction#price-precision
+ // The precision level of all trading prices is based on significant figures.
+ // All pairs on Bitfinex use up to 5 significant digits and up to 8 decimals (e.g. 1.2345, 123.45, 1234.5, 0.00012345).
+ // Prices submit with a precision larger than 5 will be cut by the API.
+ return this.decimalToPrecision (price, TRUNCATE, 8, DECIMAL_PLACES);
}
calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) {
@@ -14208,7 +13463,7 @@ module.exports = class bitfinex extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -14370,7 +13625,7 @@ module.exports = class bitfinex extends Exchange {
async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
await this.loadMarkets ();
const order = {
- 'order_id': id,
+ 'order_id': parseInt (id),
};
if (price !== undefined) {
order['price'] = this.priceToPrecision (symbol, price);
@@ -14447,8 +13702,10 @@ module.exports = class bitfinex extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': orderType,
+ 'timeInForce': undefined,
'side': side,
'price': this.safeFloat (order, 'price'),
+ 'stopPrice': undefined,
'average': this.safeFloat (order, 'avg_execution_price'),
'amount': this.safeFloat (order, 'original_amount'),
'remaining': this.safeFloat (order, 'remaining_amount'),
@@ -14499,7 +13756,17 @@ module.exports = class bitfinex extends Exchange {
return this.parseOrder (response);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1457539800000,
+ // 0.02594,
+ // 0.02594,
+ // 0.02594,
+ // 0.02594,
+ // 0.1
+ // ]
+ //
return [
this.safeInteger (ohlcv, 0),
this.safeFloat (ohlcv, 1),
@@ -14527,6 +13794,13 @@ module.exports = class bitfinex extends Exchange {
request['start'] = since;
}
const response = await this.v2GetCandlesTradeTimeframeSymbolHist (this.extend (request, params));
+ //
+ // [
+ // [1457539800000,0.02594,0.02594,0.02594,0.02594,0.1],
+ // [1457547300000,0.02577,0.02577,0.02577,0.02577,0.01],
+ // [1457550240000,0.0255,0.0253,0.0255,0.0252,3.2640000000000002],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -14573,18 +13847,23 @@ module.exports = class bitfinex extends Exchange {
}
async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
- if (code === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchTransactions() requires a currency `code` argument');
- }
await this.loadMarkets ();
- const currency = this.currency (code);
- const request = {
- 'currency': currency['id'],
- };
- if (since !== undefined) {
- request['since'] = parseInt (since / 1000);
+ let currencyId = this.safeString (params, 'currency');
+ const query = this.omit (params, 'currency');
+ let currency = undefined;
+ if (currencyId === undefined) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchTransactions() requires a currency `code` argument or a `currency` parameter');
+ } else {
+ currency = this.currency (code);
+ currencyId = currency['id'];
+ }
}
- const response = await this.privatePostHistoryMovements (this.extend (request, params));
+ query['currency'] = currencyId;
+ if (since !== undefined) {
+ query['since'] = parseInt (since / 1000);
+ }
+ const response = await this.privatePostHistoryMovements (this.extend (query, params));
//
// [
// {
@@ -14721,6 +14000,27 @@ module.exports = class bitfinex extends Exchange {
};
}
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privatePostPositions (params);
+ //
+ // [
+ // {
+ // "id":943715,
+ // "symbol":"btcusd",
+ // "status":"ACTIVE",
+ // "base":"246.94",
+ // "amount":"1.0",
+ // "timestamp":"1444141857.0",
+ // "swap":"0.0",
+ // "pl":"-2.22042"
+ // }
+ // ]
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
nonce () {
return this.milliseconds ();
}
@@ -14749,14 +14049,14 @@ module.exports = class bitfinex extends Exchange {
'request': request,
}, query);
body = this.json (query);
- query = this.encode (body);
- const payload = this.stringToBase64 (query);
+ const payload = this.stringToBase64 (body);
const secret = this.encode (this.secret);
const signature = this.hmac (payload, secret, 'sha384');
headers = {
'X-BFX-APIKEY': this.apiKey,
'X-BFX-PAYLOAD': this.decode (payload),
'X-BFX-SIGNATURE': signature,
+ 'Content-Type': 'application/json',
};
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
@@ -14778,7 +14078,7 @@ module.exports = class bitfinex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],32:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],30:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -14801,28 +14101,30 @@ module.exports = class bitfinex2 extends bitfinex {
'has': {
'CORS': false,
'cancelAllOrders': true,
+ 'cancelOrder': true,
'createDepositAddress': true,
'createLimitOrder': true,
'createMarketOrder': true,
'createOrder': true,
- 'cancelOrder': true,
'deposit': false,
'editOrder': false,
- 'fetchDepositAddress': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrder': true,
'fetchClosedOrders': false,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
'fetchFundingFees': false,
'fetchMyTrades': true,
'fetchOHLCV': true,
+ 'fetchOpenOrder': true,
'fetchOpenOrders': true,
'fetchOrder': false,
- 'fetchOpenOrder': true,
- 'fetchClosedOrder': true,
'fetchOrderTrades': true,
'fetchStatus': true,
'fetchTickers': true,
'fetchTradingFee': false,
'fetchTradingFees': false,
- 'fetchTransactions': false,
+ 'fetchTransactions': true,
'withdraw': true,
},
'timeframes': {
@@ -14875,12 +14177,14 @@ module.exports = class bitfinex2 extends bitfinex {
'conf/pub:map:currency:undl', // maps derivatives symbols to their underlying currency
'conf/pub:map:currency:pool', // maps symbols to underlying network/protocol they operate on
'conf/pub:map:currency:explorer', // maps symbols to their recognised block explorer URLs
+ 'conf/pub:map:currency:tx:fee', // maps currencies to their withdrawal fees https://github.com/ccxt/ccxt/issues/7745
'conf/pub:map:tx:method',
'conf/pub:list:{object}',
'conf/pub:list:{object}:{detail}',
'conf/pub:list:currency',
'conf/pub:list:pair:exchange',
'conf/pub:list:pair:margin',
+ 'conf/pub:list:pair:futures',
'conf/pub:list:competitions',
'conf/pub:info:{object}',
'conf/pub:info:{object}:{detail}',
@@ -15104,11 +14408,21 @@ module.exports = class bitfinex2 extends bitfinex {
}
async fetchMarkets (params = {}) {
- const response = await this.v1GetSymbolsDetails (params);
+ // todo drop v1 in favor of v2 configs
+ // pub:list:pair:exchange,pub:list:pair:margin,pub:list:pair:futures,pub:info:pair
+ const v2response = await this.publicGetConfPubListPairFutures (params);
+ const v1response = await this.v1GetSymbolsDetails (params);
+ const futuresMarketIds = this.safeValue (v2response, 0, []);
const result = [];
- for (let i = 0; i < response.length; i++) {
- const market = response[i];
+ for (let i = 0; i < v1response.length; i++) {
+ const market = v1response[i];
let id = this.safeStringUpper (market, 'pair');
+ let spot = true;
+ if (this.inArray (id, futuresMarketIds)) {
+ spot = false;
+ }
+ const futures = !spot;
+ const type = spot ? 'spot' : 'futures';
let baseId = undefined;
let quoteId = undefined;
if (id.indexOf (':') >= 0) {
@@ -15127,7 +14441,7 @@ module.exports = class bitfinex2 extends bitfinex {
quoteId = this.getCurrencyId (quoteId);
const precision = {
'price': this.safeInteger (market, 'price_precision'),
- 'amount': this.safeInteger (market, 'price_precision'),
+ 'amount': 8, // https://github.com/ccxt/ccxt/issues/7310
};
const limits = {
'amount': {
@@ -15154,14 +14468,164 @@ module.exports = class bitfinex2 extends bitfinex {
'precision': precision,
'limits': limits,
'info': market,
+ 'type': type,
'swap': false,
- 'spot': false,
- 'futures': false,
+ 'spot': spot,
+ 'futures': futures,
});
}
return result;
}
+ async fetchCurrencies (params = {}) {
+ const labels = [
+ 'pub:list:currency',
+ 'pub:map:currency:sym', // maps symbols to their API symbols, BAB > BCH
+ 'pub:map:currency:label', // verbose friendly names, BNT > Bancor
+ 'pub:map:currency:unit', // maps symbols to unit of measure where applicable
+ 'pub:map:currency:undl', // maps derivatives symbols to their underlying currency
+ 'pub:map:currency:pool', // maps symbols to underlying network/protocol they operate on
+ 'pub:map:currency:explorer', // maps symbols to their recognised block explorer URLs
+ 'pub:map:currency:tx:fee', // maps currencies to their withdrawal fees https://github.com/ccxt/ccxt/issues/7745
+ ];
+ const config = labels.join (',');
+ const request = {
+ 'config': config,
+ };
+ const response = await this.publicGetConfConfig (this.extend (request, params));
+ //
+ // [
+ //
+ // a list of symbols
+ // ["AAA","ABS","ADA"],
+ //
+ // // sym
+ // // maps symbols to their API symbols, BAB > BCH
+ // [
+ // [ 'BAB', 'BCH' ],
+ // [ 'CNHT', 'CNHt' ],
+ // [ 'DSH', 'DASH' ],
+ // [ 'IOT', 'IOTA' ],
+ // [ 'LES', 'LEO-EOS' ],
+ // [ 'LET', 'LEO-ERC20' ],
+ // [ 'STJ', 'STORJ' ],
+ // [ 'TSD', 'TUSD' ],
+ // [ 'UDC', 'USDC' ],
+ // [ 'USK', 'USDK' ],
+ // [ 'UST', 'USDt' ],
+ // [ 'USTF0', 'USDt0' ],
+ // [ 'XCH', 'XCHF' ],
+ // [ 'YYW', 'YOYOW' ],
+ // // ...
+ // ],
+ // // label
+ // // verbose friendly names, BNT > Bancor
+ // [
+ // [ 'BAB', 'Bitcoin Cash' ],
+ // [ 'BCH', 'Bitcoin Cash' ],
+ // [ 'LEO', 'Unus Sed LEO' ],
+ // [ 'LES', 'Unus Sed LEO (EOS)' ],
+ // [ 'LET', 'Unus Sed LEO (ERC20)' ],
+ // // ...
+ // ],
+ // // unit
+ // // maps symbols to unit of measure where applicable
+ // [
+ // [ 'IOT', 'Mi|MegaIOTA' ],
+ // ],
+ // // undl
+ // // maps derivatives symbols to their underlying currency
+ // [
+ // [ 'USTF0', 'UST' ],
+ // [ 'BTCF0', 'BTC' ],
+ // [ 'ETHF0', 'ETH' ],
+ // ],
+ // // pool
+ // // maps symbols to underlying network/protocol they operate on
+ // [
+ // [ 'SAN', 'ETH' ], [ 'OMG', 'ETH' ], [ 'AVT', 'ETH' ], [ 'EDO', 'ETH' ],
+ // [ 'ESS', 'ETH' ], [ 'ATD', 'EOS' ], [ 'ADD', 'EOS' ], [ 'MTO', 'EOS' ],
+ // [ 'PNK', 'ETH' ], [ 'BAB', 'BCH' ], [ 'WLO', 'XLM' ], [ 'VLD', 'ETH' ],
+ // [ 'BTT', 'TRX' ], [ 'IMP', 'ETH' ], [ 'SCR', 'ETH' ], [ 'GNO', 'ETH' ],
+ // // ...
+ // ],
+ // // explorer
+ // // maps symbols to their recognised block explorer URLs
+ // [
+ // [
+ // 'AIO',
+ // [
+ // "https://mainnet.aion.network",
+ // "https://mainnet.aion.network/#/account/VAL",
+ // "https://mainnet.aion.network/#/transaction/VAL"
+ // ]
+ // ],
+ // // ...
+ // ],
+ // // fee
+ // // maps currencies to their withdrawal fees
+ // [
+ // ["AAA",[0,0]],
+ // ["ABS",[0,131.3]],
+ // ["ADA",[0,0.3]],
+ // ],
+ // ]
+ //
+ const indexed = {
+ 'sym': this.indexBy (this.safeValue (response, 1, []), 0),
+ 'label': this.indexBy (this.safeValue (response, 2, []), 0),
+ 'unit': this.indexBy (this.safeValue (response, 3, []), 0),
+ 'undl': this.indexBy (this.safeValue (response, 4, []), 0),
+ 'pool': this.indexBy (this.safeValue (response, 5, []), 0),
+ 'explorer': this.indexBy (this.safeValue (response, 6, []), 0),
+ 'fees': this.indexBy (this.safeValue (response, 7, []), 0),
+ };
+ const ids = this.safeValue (response, 0, []);
+ const result = {};
+ for (let i = 0; i < ids.length; i++) {
+ let id = ids[i];
+ const code = this.safeCurrencyCode (id);
+ const label = this.safeValue (indexed['label'], id, []);
+ const name = this.safeString (label, 1);
+ const pool = this.safeValue (indexed['pool'], id, []);
+ const type = this.safeString (pool, 1);
+ const feeValues = this.safeValue (indexed['fees'], id, []);
+ const fees = this.safeValue (feeValues, 1, []);
+ const fee = this.safeFloat (fees, 1);
+ const precision = 8; // default precision, todo: fix "magic constants"
+ id = 'f' + id;
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': [ id, label, pool, feeValues ],
+ 'type': type,
+ 'name': name,
+ 'active': true,
+ 'fee': fee,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': 1 / Math.pow (10, precision),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': 1 / Math.pow (10, precision),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': fee,
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ return result;
+ }
+
async fetchBalance (params = {}) {
// this api call does not return the 'used' amount - use the v1 version instead (which also returns zero balances)
await this.loadMarkets ();
@@ -15285,7 +14749,7 @@ module.exports = class bitfinex2 extends bitfinex {
result[symbol] = this.parseTicker (ticker, market);
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -15471,22 +14935,32 @@ module.exports = class bitfinex2 extends bitfinex {
'limit': limit,
};
const response = await this.publicGetCandlesTradeTimeframeSymbolHist (this.extend (request, params));
+ //
+ // [
+ // [1591503840000,0.025069,0.025068,0.025069,0.025068,1.97828998],
+ // [1591504500000,0.025065,0.025065,0.025065,0.025065,1.0164],
+ // [1591504620000,0.025062,0.025062,0.025062,0.025062,0.5],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
parseOrderStatus (status) {
+ if (status === undefined) {
+ return status;
+ }
+ const parts = status.split (' ');
+ const state = this.safeString (parts, 0);
const statuses = {
'ACTIVE': 'open',
- 'PARTIALLY FILLED': 'open',
+ 'PARTIALLY': 'open',
'EXECUTED': 'closed',
'CANCELED': 'canceled',
- 'CANCELED was: PARTIALLY FILLED': 'canceled',
- 'INSUFFICIENT MARGIN': 'canceled',
- 'INSUFFICIENT BALANCE (G1) was: PARTIALLY FILLED': 'canceled',
+ 'INSUFFICIENT': 'canceled',
'RSN_DUST': 'rejected',
'RSN_PAUSE': 'rejected',
};
- return this.safeString (statuses, status, status);
+ return this.safeString (statuses, state, status);
}
parseOrder (order, market = undefined) {
@@ -15529,8 +15003,10 @@ module.exports = class bitfinex2 extends bitfinex {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': average,
@@ -15556,6 +15032,11 @@ module.exports = class bitfinex2 extends bitfinex {
if (type !== 'market') {
request['price'] = this.numberToString (price);
}
+ const clientOrderId = this.safeValue2 (params, 'cid', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['cid'] = clientOrderId;
+ params = this.omit (params, [ 'cid', 'clientOrderId' ]);
+ }
const response = await this.privatePostAuthWOrderSubmit (this.extend (request, params));
//
// [
@@ -15625,17 +15106,18 @@ module.exports = class bitfinex2 extends bitfinex {
}
async cancelOrder (id, symbol = undefined, params = {}) {
- const cid = this.safeValue (params, 'cid'); // client order id
+ const cid = this.safeValue2 (params, 'cid', 'clientOrderId'); // client order id
let request = undefined;
if (cid !== undefined) {
const cidDate = this.safeValue (params, 'cidDate'); // client order id date
if (cidDate === undefined) {
- throw new InvalidOrder (this.id + " canceling an order by client order id ('cid') requires both 'cid' and 'cid_date' ('YYYY-MM-DD')");
+ throw new InvalidOrder (this.id + " canceling an order by clientOrderId ('cid') requires both 'cid' and 'cid_date' ('YYYY-MM-DD')");
}
request = {
'cid': cid,
'cid_date': cidDate,
};
+ params = this.omit (params, [ 'cid', 'clientOrderId' ]);
} else {
request = {
'id': parseInt (id),
@@ -15796,6 +15278,16 @@ module.exports = class bitfinex2 extends bitfinex {
};
}
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'SUCCESS': 'ok',
+ 'ERROR': 'failed',
+ 'FAILURE': 'failed',
+ 'CANCELED': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
parseTransaction (transaction, currency = undefined) {
//
// withdraw
@@ -15821,38 +15313,101 @@ module.exports = class bitfinex2 extends bitfinex {
// "Invalid bitcoin address (abcdef)", // TEXT Text of the notification
// ]
//
- // todo add support for all movements, deposits and withdrawals
+ // fetchTransactions
//
- const data = this.safeValue (transaction, 4, []);
- const timestamp = this.safeInteger (transaction, 0);
+ // [
+ // 13293039, // ID
+ // 'ETH', // CURRENCY
+ // 'ETHEREUM', // CURRENCY_NAME
+ // null,
+ // null,
+ // 1574175052000, // MTS_STARTED
+ // 1574181326000, // MTS_UPDATED
+ // null,
+ // null,
+ // 'CANCELED', // STATUS
+ // null,
+ // null,
+ // -0.24, // AMOUNT, negative for withdrawals
+ // -0.00135, // FEES
+ // null,
+ // null,
+ // 'DESTINATION_ADDRESS',
+ // null,
+ // null,
+ // null,
+ // 'TRANSACTION_ID',
+ // "Purchase of 100 pizzas", // WITHDRAW_TRANSACTION_NOTE
+ // ]
+ //
+ const transactionLength = transaction.length;
+ let timestamp = undefined;
+ let updated = undefined;
let code = undefined;
- if (currency !== undefined) {
- code = currency['code'];
- }
- let feeCost = this.safeFloat (data, 8);
- if (feeCost !== undefined) {
- feeCost = Math.abs (feeCost);
- }
- const amount = this.safeFloat (data, 5);
- let id = this.safeValue (data, 0);
- let status = 'ok';
- if (id === 0) {
- id = undefined;
- status = 'failed';
+ let amount = undefined;
+ let id = undefined;
+ let status = undefined;
+ let tag = undefined;
+ let type = undefined;
+ let feeCost = undefined;
+ let txid = undefined;
+ let addressTo = undefined;
+ if (transactionLength < 9) {
+ const data = this.safeValue (transaction, 4, []);
+ timestamp = this.safeInteger (transaction, 0);
+ if (currency !== undefined) {
+ code = currency['code'];
+ }
+ feeCost = this.safeFloat (data, 8);
+ if (feeCost !== undefined) {
+ feeCost = -feeCost;
+ }
+ amount = this.safeFloat (data, 5);
+ id = this.safeValue (data, 0);
+ status = 'ok';
+ if (id === 0) {
+ id = undefined;
+ status = 'failed';
+ }
+ tag = this.safeString (data, 3);
+ type = 'withdrawal';
+ } else {
+ id = this.safeString (transaction, 0);
+ timestamp = this.safeInteger (transaction, 5);
+ updated = this.safeInteger (transaction, 6);
+ status = this.parseTransactionStatus (this.safeString (transaction, 9));
+ amount = this.safeFloat (transaction, 12);
+ if (amount !== undefined) {
+ if (amount < 0) {
+ type = 'withdrawal';
+ } else {
+ type = 'deposit';
+ }
+ }
+ feeCost = this.safeFloat (transaction, 13);
+ if (feeCost !== undefined) {
+ feeCost = -feeCost;
+ }
+ addressTo = this.safeString (transaction, 16);
+ txid = this.safeString (transaction, 20);
}
return {
'info': transaction,
'id': id,
- 'txid': undefined,
+ 'txid': txid,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'address': undefined, // this is actually the tag for XRP transfers (the address is missing)
- 'tag': this.safeString (data, 3), // refix it properly for the tag from description
- 'type': 'withdrawal',
+ 'addressFrom': undefined,
+ 'address': addressTo, // this is actually the tag for XRP transfers (the address is missing)
+ 'addressTo': addressTo,
+ 'tagFrom': undefined,
+ 'tag': tag, // refix it properly for the tag from description
+ 'tagTo': tag,
+ 'type': type,
'amount': amount,
'currency': code,
'status': status,
- 'updated': undefined,
+ 'updated': updated,
'fee': {
'currency': code,
'cost': feeCost,
@@ -15861,6 +15416,54 @@ module.exports = class bitfinex2 extends bitfinex {
};
}
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let currency = undefined;
+ const request = {};
+ let method = 'privatePostAuthRMovementsHist';
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency'] = currency['id'];
+ method = 'privatePostAuthRMovementsCurrencyHist';
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // max 1000
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // [
+ // [
+ // 13293039, // ID
+ // 'ETH', // CURRENCY
+ // 'ETHEREUM', // CURRENCY_NAME
+ // null,
+ // null,
+ // 1574175052000, // MTS_STARTED
+ // 1574181326000, // MTS_UPDATED
+ // null,
+ // null,
+ // 'CANCELED', // STATUS
+ // null,
+ // null,
+ // -0.24, // AMOUNT, negative for withdrawals
+ // -0.00135, // FEES
+ // null,
+ // null,
+ // 'DESTINATION_ADDRESS',
+ // null,
+ // null,
+ // null,
+ // 'TRANSACTION_ID',
+ // "Purchase of 100 pizzas", // WITHDRAW_TRANSACTION_NOTE
+ // ]
+ // ]
+ //
+ return this.parseTransactions (response, currency, since, limit);
+ }
+
async withdraw (code, amount, address, tag = undefined, params = {}) {
this.checkAddress (address);
await this.loadMarkets ();
@@ -15909,6 +15512,47 @@ module.exports = class bitfinex2 extends bitfinex {
});
}
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privatePostPositions (params);
+ //
+ // [
+ // [
+ // "tBTCUSD", // SYMBOL
+ // "ACTIVE", // STATUS
+ // 0.0195, // AMOUNT
+ // 8565.0267019, // BASE_PRICE
+ // 0, // MARGIN_FUNDING
+ // 0, // MARGIN_FUNDING_TYPE
+ // -0.33455568705000516, // PL
+ // -0.0003117550117425625, // PL_PERC
+ // 7045.876419249083, // PRICE_LIQ
+ // 3.0673001895895604, // LEVERAGE
+ // null, // _PLACEHOLDER
+ // 142355652, // POSITION_ID
+ // 1574002216000, // MTS_CREATE
+ // 1574002216000, // MTS_UPDATE
+ // null, // _PLACEHOLDER
+ // 0, // TYPE
+ // null, // _PLACEHOLDER
+ // 0, // COLLATERAL
+ // 0, // COLLATERAL_MIN
+ // // META
+ // {
+ // "reason":"TRADE",
+ // "order_id":34271018124,
+ // "liq_stage":null,
+ // "trade_price":"8565.0267019",
+ // "trade_amount":"0.0195",
+ // "order_id_oppo":34277498022
+ // }
+ // ]
+ // ]
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
nonce () {
return this.milliseconds ();
}
@@ -15973,7 +15617,7 @@ module.exports = class bitfinex2 extends bitfinex {
}
};
-},{"./base/errors":9,"./bitfinex.js":31}],33:[function(require,module,exports){
+},{"./base/errors":7,"./bitfinex.js":29}],31:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -15991,19 +15635,27 @@ module.exports = class bitflyer extends Exchange {
'countries': [ 'JP' ],
'version': 'v1',
'rateLimit': 1000, // their nonce-timestamp is in seconds...
+ 'hostname': 'bitflyer.com', // or bitflyer.com
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'withdraw': true,
- 'fetchMyTrades': true,
- 'fetchOrders': true,
- 'fetchOrder': 'emulated',
- 'fetchOpenOrders': 'emulated',
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': 'emulated',
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': 'emulated',
+ 'fetchOrder': 'emulated',
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/28051642-56154182-660e-11e7-9b0d-6042d1e6edd8.jpg',
- 'api': 'https://api.bitflyer.jp',
- 'www': 'https://bitflyer.jp',
+ 'api': 'https://api.{hostname}',
+ 'www': 'https://bitflyer.com',
'doc': 'https://lightning.bitflyer.com/docs?lang=en',
},
'api': {
@@ -16310,16 +15962,8 @@ module.exports = class bitflyer extends Exchange {
const status = this.parseOrderStatus (this.safeString (order, 'child_order_state'));
const type = this.safeStringLower (order, 'child_order_type');
const side = this.safeStringLower (order, 'side');
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'product_code');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'product_code');
+ const symbol = this.safeSymbol (marketId, market);
let fee = undefined;
const feeCost = this.safeFloat (order, 'total_commission');
if (feeCost !== undefined) {
@@ -16340,8 +15984,10 @@ module.exports = class bitflyer extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -16412,6 +16058,36 @@ module.exports = class bitflyer extends Exchange {
return this.parseTrades (response, market, since, limit);
}
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbols === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchPositions requires a `symbols` argument, exactly one symbol in an array');
+ }
+ await this.loadMarkets ();
+ const request = {
+ 'product_code': this.marketIds (symbols),
+ };
+ const response = await this.privateGetpositions (this.extend (request, params));
+ //
+ // [
+ // {
+ // "product_code": "FX_BTC_JPY",
+ // "side": "BUY",
+ // "price": 36000,
+ // "size": 10,
+ // "commission": 0,
+ // "swap_point_accumulate": -35,
+ // "require_collateral": 120000,
+ // "open_date": "2015-11-03T10:04:45.011",
+ // "leverage": 3,
+ // "pnl": 965,
+ // "sfd": -0.5
+ // }
+ // ]
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
async withdraw (code, amount, address, tag = undefined, params = {}) {
this.checkAddress (address);
await this.loadMarkets ();
@@ -16443,7 +16119,8 @@ module.exports = class bitflyer extends Exchange {
request += '?' + this.urlencode (params);
}
}
- const url = this.urls['api'] + request;
+ const baseUrl = this.implodeParams (this.urls['api'], { 'hostname': this.hostname });
+ const url = baseUrl + request;
if (api === 'private') {
this.checkRequiredCredentials ();
const nonce = this.nonce ().toString ();
@@ -16465,13 +16142,13 @@ module.exports = class bitflyer extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],34:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],32:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, AuthenticationError, OrderNotFound, InsufficientFunds, DDoSProtection } = require ('./base/errors');
+const { ExchangeError, AuthenticationError, OrderNotFound, InsufficientFunds, DDoSProtection, PermissionDenied } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -16483,19 +16160,20 @@ module.exports = class bitforex extends Exchange {
'countries': [ 'CN' ],
'version': 'v1',
'has': {
- 'fetchBalance': true,
- 'fetchMarkets': true,
- 'createOrder': true,
'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': false,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
'fetchTicker': true,
'fetchTickers': false,
- 'fetchMyTrades': false,
'fetchTrades': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'fetchOHLCV': true,
},
'timeframes': {
'1m': '1min',
@@ -16511,7 +16189,7 @@ module.exports = class bitforex extends Exchange {
'1M': '1month',
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/44310033-69e9e600-a3d8-11e8-873d-54d74d1bc4e4.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295553-1160ec00-c50e-11ea-8ea0-df79276a9646.jpg',
'api': 'https://api.bitforex.com',
'www': 'https://www.bitforex.com',
'doc': 'https://github.com/githubdev2020/API_Doc_en/wiki',
@@ -16689,12 +16367,15 @@ module.exports = class bitforex extends Exchange {
},
},
'commonCurrencies': {
+ 'CREDIT': 'TerraCredit',
+ 'IQ': 'IQ.Cash',
'UOS': 'UOS Network',
},
'exceptions': {
'4004': OrderNotFound,
'1013': AuthenticationError,
'1016': AuthenticationError,
+ '1017': PermissionDenied, // {"code":"1017","success":false,"time":1602670594367,"message":"IP not allow"}
'3002': InsufficientFunds,
'10204': DDoSProtection,
},
@@ -16848,7 +16529,18 @@ module.exports = class bitforex extends Exchange {
};
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "close":0.02505143,
+ // "currencyVol":0,
+ // "high":0.02506422,
+ // "low":0.02505143,
+ // "open":0.02506095,
+ // "time":1591508940000,
+ // "vol":51.1869
+ // }
+ //
return [
this.safeInteger (ohlcv, 'time'),
this.safeFloat (ohlcv, 'open'),
@@ -16870,8 +16562,19 @@ module.exports = class bitforex extends Exchange {
request['size'] = limit; // default 1, max 600
}
const response = await this.publicGetApiV1MarketKline (this.extend (request, params));
- const ohlcvs = this.safeValue (response, 'data', []);
- return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+ //
+ // {
+ // "data":[
+ // {"close":0.02505143,"currencyVol":0,"high":0.02506422,"low":0.02505143,"open":0.02506095,"time":1591508940000,"vol":51.1869},
+ // {"close":0.02503914,"currencyVol":0,"high":0.02506687,"low":0.02503914,"open":0.02505358,"time":1591509000000,"vol":9.1082},
+ // {"close":0.02505172,"currencyVol":0,"high":0.02507466,"low":0.02503895,"open":0.02506371,"time":1591509060000,"vol":63.7431},
+ // ],
+ // "success":true,
+ // "time":1591509427131
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -16940,8 +16643,10 @@ module.exports = class bitforex extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -17067,13 +16772,2920 @@ module.exports = class bitforex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],35:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],33:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, ExchangeNotAvailable, OnMaintenance, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol, RateLimitExceeded } = require ('./base/errors');
+const { TICK_SIZE } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class bitget extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'bitget',
+ 'name': 'Bitget',
+ 'countries': [ 'SG' ],
+ 'version': 'v3',
+ 'rateLimit': 1000, // up to 3000 requests per 5 minutes ≈ 600 requests per minute ≈ 10 requests per second ≈ 100 ms
+ 'has': {
+ 'cancelOrder': true,
+ 'cancelOrders': true,
+ 'CORS': false,
+ 'createOrder': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOpenOrders': true,
+ 'fetchClosedOrders': true,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '5m': '5m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '2h': '2h',
+ '4h': '4h',
+ '6h': '6h',
+ '12h': '12h',
+ '1d': '1d',
+ '1w': '1w',
+ },
+ 'hostname': 'bitget.com',
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/51840849/88317935-a8a21c80-cd22-11ea-8e2b-4b9fac5975eb.jpg',
+ 'api': {
+ 'data': 'https://api.{hostname}',
+ 'api': 'https://api.{hostname}',
+ 'capi': 'https://capi.{hostname}',
+ 'swap': 'https://capi.{hostname}',
+ },
+ 'www': 'https://www.bitget.com',
+ 'doc': [
+ 'https://bitgetlimited.github.io/apidoc/en/swap',
+ 'https://bitgetlimited.github.io/apidoc/en/spot',
+ ],
+ 'fees': 'https://www.bitget.cc/zh-CN/rate?tab=1',
+ 'test': {
+ 'rest': 'https://testnet.bitget.com',
+ },
+ 'referral': 'https://www.bitget.com/expressly?languageType=0&channelCode=ccxt&vipCode=tg9j',
+ },
+ 'api': {
+ 'data': {
+ 'get': [
+ 'market/history/kline', // Kline data
+ 'market/detail/merged', // Get aggregated ticker
+ 'market/tickers', // Get all trading tickers
+ 'market/allticker', // Get all trading market method 2
+ 'market/depth', // Get Market Depth Data
+ 'market/trade', // Get Trade Detail Data
+ 'market/history/trade', // Get record of trading
+ 'market/detail', // Get Market Detail 24h Volume
+ 'common/symbols', // Query all trading pairs and accuracy supported in the station
+ 'common/currencys', // Query all currencies supported in the station
+ 'common/timestamp', // Query system current time
+ ],
+ },
+ 'api': {
+ 'get': [
+ 'account/accounts', // Get all accounts of current user(即account_id)。
+ 'accounts/{account_id}/balance', // Get the balance of the specified account
+ 'order/orders', // Query order, deprecated
+ 'order/orders/openOrders',
+ 'order/orders/history',
+ 'order/deposit_withdraw', // Query assets history
+ ],
+ 'post': [
+ 'order/orders/place', // Place order
+ 'order/orders/{order_id}/submitcancel', // Request to cancel an order request
+ 'order/orders/batchcancel', // Bulk order cancellation
+ 'order/orders/{order_id}', // Query an order details
+ 'order/orders/{order_id}/matchresults', // Query the transaction details of an order
+ 'order/matchresults', // Query current order, order history
+ ],
+ },
+ 'capi': {
+ 'get': [
+ 'market/time',
+ 'market/contracts',
+ 'market/depth',
+ 'market/tickers',
+ 'market/ticker',
+ 'market/trades',
+ 'market/candles',
+ 'market/index',
+ 'market/open_count',
+ 'market/open_interest',
+ 'market/price_limit',
+ 'market/funding_time',
+ 'market/mark_price',
+ 'market/open_count',
+ 'market/historyFundRate',
+ ],
+ },
+ 'swap': {
+ 'get': [
+ 'account/accounts',
+ 'account/account',
+ 'account/settings',
+ 'position/allPosition',
+ 'position/singlePosition',
+ 'position/holds',
+ 'order/detail',
+ 'order/orders',
+ 'order/fills',
+ 'order/current',
+ 'order/currentPlan', // conditional
+ 'order/history',
+ 'order/historyPlan', // conditional
+ 'trace/closeTrack',
+ 'trace/currentTrack',
+ 'trace/historyTrack',
+ ],
+ 'post': [
+ 'account/leverage',
+ 'account/adjustMargin',
+ 'account/modifyAutoAppendMargin',
+ 'order/placeOrder',
+ 'order/batchOrders',
+ 'order/cancel_order',
+ 'order/cancel_batch_orders',
+ 'order/plan_order',
+ 'order/cancel_plan',
+ 'position/changeHoldModel',
+ ],
+ },
+ },
+ 'fees': {
+ 'spot': {
+ 'taker': 0.002,
+ 'maker': 0.002,
+ },
+ 'swap': {
+ 'taker': 0.0006,
+ 'maker': 0.0004,
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ 'password': true,
+ },
+ 'exceptions': {
+ // http error codes
+ // 400 Bad Request — Invalid request format
+ // 401 Unauthorized — Invalid API Key
+ // 403 Forbidden — You do not have access to the requested resource
+ // 404 Not Found
+ // 500 Internal Server Error — We had a problem with our server
+ 'exact': {
+ '1': ExchangeError, // { "code": 1, "message": "System error" }
+ // undocumented
+ 'failure to get a peer from the ring-balancer': ExchangeNotAvailable, // { "message": "failure to get a peer from the ring-balancer" }
+ '4010': PermissionDenied, // { "code": 4010, "message": "For the security of your funds, withdrawals are not permitted within 24 hours after changing fund password / mobile number / Google Authenticator settings " }
+ // common
+ // '0': ExchangeError, // 200 successful,when the order placement / cancellation / operation is successful
+ '4001': ExchangeError, // no data received in 30s
+ '4002': ExchangeError, // Buffer full. cannot write data
+ // --------------------------------------------------------
+ '30001': AuthenticationError, // { "code": 30001, "message": 'request header "OK_ACCESS_KEY" cannot be blank'}
+ '30002': AuthenticationError, // { "code": 30002, "message": 'request header "OK_ACCESS_SIGN" cannot be blank'}
+ '30003': AuthenticationError, // { "code": 30003, "message": 'request header "OK_ACCESS_TIMESTAMP" cannot be blank'}
+ '30004': AuthenticationError, // { "code": 30004, "message": 'request header "OK_ACCESS_PASSPHRASE" cannot be blank'}
+ '30005': InvalidNonce, // { "code": 30005, "message": "invalid OK_ACCESS_TIMESTAMP" }
+ '30006': AuthenticationError, // { "code": 30006, "message": "invalid OK_ACCESS_KEY" }
+ '30007': BadRequest, // { "code": 30007, "message": 'invalid Content_Type, please use "application/json" format'}
+ '30008': RequestTimeout, // { "code": 30008, "message": "timestamp request expired" }
+ '30009': ExchangeError, // { "code": 30009, "message": "system error" }
+ '30010': AuthenticationError, // { "code": 30010, "message": "API validation failed" }
+ '30011': PermissionDenied, // { "code": 30011, "message": "invalid IP" }
+ '30012': AuthenticationError, // { "code": 30012, "message": "invalid authorization" }
+ '30013': AuthenticationError, // { "code": 30013, "message": "invalid sign" }
+ '30014': DDoSProtection, // { "code": 30014, "message": "request too frequent" }
+ '30015': AuthenticationError, // { "code": 30015, "message": 'request header "OK_ACCESS_PASSPHRASE" incorrect'}
+ '30016': ExchangeError, // { "code": 30015, "message": "you are using v1 apiKey, please use v1 endpoint. If you would like to use v3 endpoint, please subscribe to v3 apiKey" }
+ '30017': ExchangeError, // { "code": 30017, "message": "apikey's broker id does not match" }
+ '30018': ExchangeError, // { "code": 30018, "message": "apikey's domain does not match" }
+ '30019': ExchangeNotAvailable, // { "code": 30019, "message": "Api is offline or unavailable" }
+ '30020': BadRequest, // { "code": 30020, "message": "body cannot be blank" }
+ '30021': BadRequest, // { "code": 30021, "message": "Json data format error" }, { "code": 30021, "message": "json data format error" }
+ '30022': PermissionDenied, // { "code": 30022, "message": "Api has been frozen" }
+ '30023': BadRequest, // { "code": 30023, "message": "{0} parameter cannot be blank" }
+ '30024': BadSymbol, // {"code":30024,"message":"\"instrument_id\" is an invalid parameter"}
+ '30025': BadRequest, // { "code": 30025, "message": "{0} parameter category error" }
+ '30026': DDoSProtection, // { "code": 30026, "message": "requested too frequent" }
+ '30027': AuthenticationError, // { "code": 30027, "message": "login failure" }
+ '30028': PermissionDenied, // { "code": 30028, "message": "unauthorized execution" }
+ '30029': AccountSuspended, // { "code": 30029, "message": "account suspended" }
+ '30030': ExchangeError, // { "code": 30030, "message": "endpoint request failed. Please try again" }
+ '30031': BadRequest, // { "code": 30031, "message": "token does not exist" }
+ '30032': BadSymbol, // { "code": 30032, "message": "pair does not exist" }
+ '30033': BadRequest, // { "code": 30033, "message": "exchange domain does not exist" }
+ '30034': ExchangeError, // { "code": 30034, "message": "exchange ID does not exist" }
+ '30035': ExchangeError, // { "code": 30035, "message": "trading is not supported in this website" }
+ '30036': ExchangeError, // { "code": 30036, "message": "no relevant data" }
+ '30037': ExchangeNotAvailable, // { "code": 30037, "message": "endpoint is offline or unavailable" }
+ // '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" }
+ '30038': OnMaintenance, // {"client_oid":"","code":"30038","error_code":"30038","error_message":"Matching engine is being upgraded. Please try in about 1 minute.","message":"Matching engine is being upgraded. Please try in about 1 minute.","order_id":"-1","result":false}
+ // futures
+ '32001': AccountSuspended, // { "code": 32001, "message": "futures account suspended" }
+ '32002': PermissionDenied, // { "code": 32002, "message": "futures account does not exist" }
+ '32003': CancelPending, // { "code": 32003, "message": "canceling, please wait" }
+ '32004': ExchangeError, // { "code": 32004, "message": "you have no unfilled orders" }
+ '32005': InvalidOrder, // { "code": 32005, "message": "max order quantity" }
+ '32006': InvalidOrder, // { "code": 32006, "message": "the order price or trigger price exceeds USD 1 million" }
+ '32007': InvalidOrder, // { "code": 32007, "message": "leverage level must be the same for orders on the same side of the contract" }
+ '32008': InvalidOrder, // { "code": 32008, "message": "Max. positions to open (cross margin)" }
+ '32009': InvalidOrder, // { "code": 32009, "message": "Max. positions to open (fixed margin)" }
+ '32010': ExchangeError, // { "code": 32010, "message": "leverage cannot be changed with open positions" }
+ '32011': ExchangeError, // { "code": 32011, "message": "futures status error" }
+ '32012': ExchangeError, // { "code": 32012, "message": "futures order update error" }
+ '32013': ExchangeError, // { "code": 32013, "message": "token type is blank" }
+ '32014': ExchangeError, // { "code": 32014, "message": "your number of contracts closing is larger than the number of contracts available" }
+ '32015': ExchangeError, // { "code": 32015, "message": "margin ratio is lower than 100% before opening positions" }
+ '32016': ExchangeError, // { "code": 32016, "message": "margin ratio is lower than 100% after opening position" }
+ '32017': ExchangeError, // { "code": 32017, "message": "no BBO" }
+ '32018': ExchangeError, // { "code": 32018, "message": "the order quantity is less than 1, please try again" }
+ '32019': ExchangeError, // { "code": 32019, "message": "the order price deviates from the price of the previous minute by more than 3%" }
+ '32020': ExchangeError, // { "code": 32020, "message": "the price is not in the range of the price limit" }
+ '32021': ExchangeError, // { "code": 32021, "message": "leverage error" }
+ '32022': ExchangeError, // { "code": 32022, "message": "this function is not supported in your country or region according to the regulations" }
+ '32023': ExchangeError, // { "code": 32023, "message": "this account has outstanding loan" }
+ '32024': ExchangeError, // { "code": 32024, "message": "order cannot be placed during delivery" }
+ '32025': ExchangeError, // { "code": 32025, "message": "order cannot be placed during settlement" }
+ '32026': ExchangeError, // { "code": 32026, "message": "your account is restricted from opening positions" }
+ '32027': ExchangeError, // { "code": 32027, "message": "cancelled over 20 orders" }
+ '32028': AccountSuspended, // { "code": 32028, "message": "account is suspended and liquidated" }
+ '32029': ExchangeError, // { "code": 32029, "message": "order info does not exist" }
+ '32030': InvalidOrder, // The order cannot be cancelled
+ '32031': ArgumentsRequired, // client_oid or order_id is required.
+ '32038': AuthenticationError, // User does not exist
+ '32040': ExchangeError, // User have open contract orders or position
+ '32044': ExchangeError, // { "code": 32044, "message": "The margin ratio after submitting this order is lower than the minimum requirement ({0}) for your tier." }
+ '32045': ExchangeError, // String of commission over 1 million
+ '32046': ExchangeError, // Each user can hold up to 10 trade plans at the same time
+ '32047': ExchangeError, // system error
+ '32048': InvalidOrder, // Order strategy track range error
+ '32049': ExchangeError, // Each user can hold up to 10 track plans at the same time
+ '32050': InvalidOrder, // Order strategy rang error
+ '32051': InvalidOrder, // Order strategy ice depth error
+ '32052': ExchangeError, // String of commission over 100 thousand
+ '32053': ExchangeError, // Each user can hold up to 6 ice plans at the same time
+ '32057': ExchangeError, // The order price is zero. Market-close-all function cannot be executed
+ '32054': ExchangeError, // Trade not allow
+ '32055': InvalidOrder, // cancel order error
+ '32056': ExchangeError, // iceberg per order average should between {0}-{1} contracts
+ '32058': ExchangeError, // Each user can hold up to 6 initiative plans at the same time
+ '32059': InvalidOrder, // Total amount should exceed per order amount
+ '32060': InvalidOrder, // Order strategy type error
+ '32061': InvalidOrder, // Order strategy initiative limit error
+ '32062': InvalidOrder, // Order strategy initiative range error
+ '32063': InvalidOrder, // Order strategy initiative rate error
+ '32064': ExchangeError, // Time Stringerval of orders should set between 5-120s
+ '32065': ExchangeError, // Close amount exceeds the limit of Market-close-all (999 for BTC, and 9999 for the rest tokens)
+ '32066': ExchangeError, // You have open orders. Please cancel all open orders before changing your leverage level.
+ '32067': ExchangeError, // Account equity < required margin in this setting. Please adjust your leverage level again.
+ '32068': ExchangeError, // The margin for this position will fall short of the required margin in this setting. Please adjust your leverage level or increase your margin to proceed.
+ '32069': ExchangeError, // Target leverage level too low. Your account balance is insufficient to cover the margin required. Please adjust the leverage level again.
+ '32070': ExchangeError, // Please check open position or unfilled order
+ '32071': ExchangeError, // Your current liquidation mode does not support this action.
+ '32072': ExchangeError, // The highest available margin for your order’s tier is {0}. Please edit your margin and place a new order.
+ '32073': ExchangeError, // The action does not apply to the token
+ '32074': ExchangeError, // The number of contracts of your position, open orders, and the current order has exceeded the maximum order limit of this asset.
+ '32075': ExchangeError, // Account risk rate breach
+ '32076': ExchangeError, // Liquidation of the holding position(s) at market price will require cancellation of all pending close orders of the contracts.
+ '32077': ExchangeError, // Your margin for this asset in futures account is insufficient and the position has been taken over for liquidation. (You will not be able to place orders, close positions, transfer funds, or add margin during this period of time. Your account will be restored after the liquidation is complete.)
+ '32078': ExchangeError, // Please cancel all open orders before switching the liquidation mode(Please cancel all open orders before switching the liquidation mode)
+ '32079': ExchangeError, // Your open positions are at high risk.(Please add margin or reduce positions before switching the mode)
+ '32080': ExchangeError, // Funds cannot be transferred out within 30 minutes after futures settlement
+ '32083': ExchangeError, // The number of contracts should be a positive multiple of %%. Please place your order again
+ // token and margin trading
+ '33001': PermissionDenied, // { "code": 33001, "message": "margin account for this pair is not enabled yet" }
+ '33002': AccountSuspended, // { "code": 33002, "message": "margin account for this pair is suspended" }
+ '33003': InsufficientFunds, // { "code": 33003, "message": "no loan balance" }
+ '33004': ExchangeError, // { "code": 33004, "message": "loan amount cannot be smaller than the minimum limit" }
+ '33005': ExchangeError, // { "code": 33005, "message": "repayment amount must exceed 0" }
+ '33006': ExchangeError, // { "code": 33006, "message": "loan order not found" }
+ '33007': ExchangeError, // { "code": 33007, "message": "status not found" }
+ '33008': InsufficientFunds, // { "code": 33008, "message": "loan amount cannot exceed the maximum limit" }
+ '33009': ExchangeError, // { "code": 33009, "message": "user ID is blank" }
+ '33010': ExchangeError, // { "code": 33010, "message": "you cannot cancel an order during session 2 of call auction" }
+ '33011': ExchangeError, // { "code": 33011, "message": "no new market data" }
+ '33012': ExchangeError, // { "code": 33012, "message": "order cancellation failed" }
+ '33013': InvalidOrder, // { "code": 33013, "message": "order placement failed" }
+ '33014': OrderNotFound, // { "code": 33014, "message": "order does not exist" }
+ '33015': InvalidOrder, // { "code": 33015, "message": "exceeded maximum limit" }
+ '33016': ExchangeError, // { "code": 33016, "message": "margin trading is not open for this token" }
+ '33017': InsufficientFunds, // { "code": 33017, "message": "insufficient balance" }
+ '33018': ExchangeError, // { "code": 33018, "message": "this parameter must be smaller than 1" }
+ '33020': ExchangeError, // { "code": 33020, "message": "request not supported" }
+ '33021': BadRequest, // { "code": 33021, "message": "token and the pair do not match" }
+ '33022': InvalidOrder, // { "code": 33022, "message": "pair and the order do not match" }
+ '33023': ExchangeError, // { "code": 33023, "message": "you can only place market orders during call auction" }
+ '33024': InvalidOrder, // { "code": 33024, "message": "trading amount too small" }
+ '33025': InvalidOrder, // { "code": 33025, "message": "base token amount is blank" }
+ '33026': ExchangeError, // { "code": 33026, "message": "transaction completed" }
+ '33027': InvalidOrder, // { "code": 33027, "message": "cancelled order or order cancelling" }
+ '33028': InvalidOrder, // { "code": 33028, "message": "the decimal places of the trading price exceeded the limit" }
+ '33029': InvalidOrder, // { "code": 33029, "message": "the decimal places of the trading size exceeded the limit" }
+ '33034': ExchangeError, // { "code": 33034, "message": "You can only place limit order after Call Auction has started" }
+ '33035': ExchangeError, // This type of order cannot be canceled(This type of order cannot be canceled)
+ '33036': ExchangeError, // Exceeding the limit of entrust order
+ '33037': ExchangeError, // The buy order price should be lower than 130% of the trigger price
+ '33038': ExchangeError, // The sell order price should be higher than 70% of the trigger price
+ '33039': ExchangeError, // The limit of callback rate is 0 < x <= 5%
+ '33040': ExchangeError, // The trigger price of a buy order should be lower than the latest transaction price
+ '33041': ExchangeError, // The trigger price of a sell order should be higher than the latest transaction price
+ '33042': ExchangeError, // The limit of price variance is 0 < x <= 1%
+ '33043': ExchangeError, // The total amount must be larger than 0
+ '33044': ExchangeError, // The average amount should be 1/1000 * total amount <= x <= total amount
+ '33045': ExchangeError, // The price should not be 0, including trigger price, order price, and price limit
+ '33046': ExchangeError, // Price variance should be 0 < x <= 1%
+ '33047': ExchangeError, // Sweep ratio should be 0 < x <= 100%
+ '33048': ExchangeError, // Per order limit: Total amount/1000 < x <= Total amount
+ '33049': ExchangeError, // Total amount should be X > 0
+ '33050': ExchangeError, // Time interval should be 5 <= x <= 120s
+ '33051': ExchangeError, // cancel order number not higher limit: plan and track entrust no more than 10, ice and time entrust no more than 6
+ '33059': BadRequest, // { "code": 33059, "message": "client_oid or order_id is required" }
+ '33060': BadRequest, // { "code": 33060, "message": "Only fill in either parameter client_oid or order_id" }
+ '33061': ExchangeError, // Value of a single market price order cannot exceed 100,000 USD
+ '33062': ExchangeError, // The leverage ratio is too high. The borrowed position has exceeded the maximum position of this leverage ratio. Please readjust the leverage ratio
+ '33063': ExchangeError, // Leverage multiple is too low, there is insufficient margin in the account, please readjust the leverage ratio
+ '33064': ExchangeError, // The setting of the leverage ratio cannot be less than 2, please readjust the leverage ratio
+ '33065': ExchangeError, // Leverage ratio exceeds maximum leverage ratio, please readjust leverage ratio
+ // account
+ '21009': ExchangeError, // Funds cannot be transferred out within 30 minutes after swap settlement(Funds cannot be transferred out within 30 minutes after swap settlement)
+ '34001': PermissionDenied, // { "code": 34001, "message": "withdrawal suspended" }
+ '34002': InvalidAddress, // { "code": 34002, "message": "please add a withdrawal address" }
+ '34003': ExchangeError, // { "code": 34003, "message": "sorry, this token cannot be withdrawn to xx at the moment" }
+ '34004': ExchangeError, // { "code": 34004, "message": "withdrawal fee is smaller than minimum limit" }
+ '34005': ExchangeError, // { "code": 34005, "message": "withdrawal fee exceeds the maximum limit" }
+ '34006': ExchangeError, // { "code": 34006, "message": "withdrawal amount is lower than the minimum limit" }
+ '34007': ExchangeError, // { "code": 34007, "message": "withdrawal amount exceeds the maximum limit" }
+ '34008': InsufficientFunds, // { "code": 34008, "message": "insufficient balance" }
+ '34009': ExchangeError, // { "code": 34009, "message": "your withdrawal amount exceeds the daily limit" }
+ '34010': ExchangeError, // { "code": 34010, "message": "transfer amount must be larger than 0" }
+ '34011': ExchangeError, // { "code": 34011, "message": "conditions not met" }
+ '34012': ExchangeError, // { "code": 34012, "message": "the minimum withdrawal amount for NEO is 1, and the amount must be an integer" }
+ '34013': ExchangeError, // { "code": 34013, "message": "please transfer" }
+ '34014': ExchangeError, // { "code": 34014, "message": "transfer limited" }
+ '34015': ExchangeError, // { "code": 34015, "message": "subaccount does not exist" }
+ '34016': PermissionDenied, // { "code": 34016, "message": "transfer suspended" }
+ '34017': AccountSuspended, // { "code": 34017, "message": "account suspended" }
+ '34018': AuthenticationError, // { "code": 34018, "message": "incorrect trades password" }
+ '34019': PermissionDenied, // { "code": 34019, "message": "please bind your email before withdrawal" }
+ '34020': PermissionDenied, // { "code": 34020, "message": "please bind your funds password before withdrawal" }
+ '34021': InvalidAddress, // { "code": 34021, "message": "Not verified address" }
+ '34022': ExchangeError, // { "code": 34022, "message": "Withdrawals are not available for sub accounts" }
+ '34023': PermissionDenied, // { "code": 34023, "message": "Please enable futures trading before transferring your funds" }
+ '34026': ExchangeError, // transfer too frequently(transfer too frequently)
+ '34036': ExchangeError, // Parameter is incorrect, please refer to API documentation
+ '34037': ExchangeError, // Get the sub-account balance interface, account type is not supported
+ '34038': ExchangeError, // Since your C2C transaction is unusual, you are restricted from fund transfer. Please contact our customer support to cancel the restriction
+ '34039': ExchangeError, // You are now restricted from transferring out your funds due to abnormal trades on C2C Market. Please transfer your fund on our website or app instead to verify your identity
+ // swap
+ '35001': ExchangeError, // { "code": 35001, "message": "Contract does not exist" }
+ '35002': ExchangeError, // { "code": 35002, "message": "Contract settling" }
+ '35003': ExchangeError, // { "code": 35003, "message": "Contract paused" }
+ '35004': ExchangeError, // { "code": 35004, "message": "Contract pending settlement" }
+ '35005': AuthenticationError, // { "code": 35005, "message": "User does not exist" }
+ '35008': InvalidOrder, // { "code": 35008, "message": "Risk ratio too high" }
+ '35010': InvalidOrder, // { "code": 35010, "message": "Position closing too large" }
+ '35012': InvalidOrder, // { "code": 35012, "message": "Incorrect order size" }
+ '35014': InvalidOrder, // { "code": 35014, "message": "Order price is not within limit" }
+ '35015': InvalidOrder, // { "code": 35015, "message": "Invalid leverage level" }
+ '35017': ExchangeError, // { "code": 35017, "message": "Open orders exist" }
+ '35019': InvalidOrder, // { "code": 35019, "message": "Order size too large" }
+ '35020': InvalidOrder, // { "code": 35020, "message": "Order price too high" }
+ '35021': InvalidOrder, // { "code": 35021, "message": "Order size exceeded current tier limit" }
+ '35022': ExchangeError, // { "code": 35022, "message": "Contract status error" }
+ '35024': ExchangeError, // { "code": 35024, "message": "Contract not initialized" }
+ '35025': InsufficientFunds, // { "code": 35025, "message": "No account balance" }
+ '35026': ExchangeError, // { "code": 35026, "message": "Contract settings not initialized" }
+ '35029': OrderNotFound, // { "code": 35029, "message": "Order does not exist" }
+ '35030': InvalidOrder, // { "code": 35030, "message": "Order size too large" }
+ '35031': InvalidOrder, // { "code": 35031, "message": "Cancel order size too large" }
+ '35032': ExchangeError, // { "code": 35032, "message": "Invalid user status" }
+ '35037': ExchangeError, // No last traded price in cache
+ '35039': ExchangeError, // { "code": 35039, "message": "Open order quantity exceeds limit" }
+ '35040': InvalidOrder, // {"error_message":"Invalid order type","result":"true","error_code":"35040","order_id":"-1"}
+ '35044': ExchangeError, // { "code": 35044, "message": "Invalid order status" }
+ '35046': InsufficientFunds, // { "code": 35046, "message": "Negative account balance" }
+ '35047': InsufficientFunds, // { "code": 35047, "message": "Insufficient account balance" }
+ '35048': ExchangeError, // { "code": 35048, "message": "User contract is frozen and liquidating" }
+ '35049': InvalidOrder, // { "code": 35049, "message": "Invalid order type" }
+ '35050': InvalidOrder, // { "code": 35050, "message": "Position settings are blank" }
+ '35052': InsufficientFunds, // { "code": 35052, "message": "Insufficient cross margin" }
+ '35053': ExchangeError, // { "code": 35053, "message": "Account risk too high" }
+ '35055': InsufficientFunds, // { "code": 35055, "message": "Insufficient account balance" }
+ '35057': ExchangeError, // { "code": 35057, "message": "No last traded price" }
+ '35058': ExchangeError, // { "code": 35058, "message": "No limit" }
+ '35059': BadRequest, // { "code": 35059, "message": "client_oid or order_id is required" }
+ '35060': BadRequest, // { "code": 35060, "message": "Only fill in either parameter client_oid or order_id" }
+ '35061': BadRequest, // { "code": 35061, "message": "Invalid instrument_id" }
+ '35062': InvalidOrder, // { "code": 35062, "message": "Invalid match_price" }
+ '35063': InvalidOrder, // { "code": 35063, "message": "Invalid order_size" }
+ '35064': InvalidOrder, // { "code": 35064, "message": "Invalid client_oid" }
+ '35066': InvalidOrder, // Order interval error
+ '35067': InvalidOrder, // Time-weighted order ratio error
+ '35068': InvalidOrder, // Time-weighted order range error
+ '35069': InvalidOrder, // Time-weighted single transaction limit error
+ '35070': InvalidOrder, // Algo order type error
+ '35071': InvalidOrder, // Order total must be larger than single order limit
+ '35072': InvalidOrder, // Maximum 6 unfulfilled time-weighted orders can be held at the same time
+ '35073': InvalidOrder, // Order price is 0. Market-close-all not available
+ '35074': InvalidOrder, // Iceberg order single transaction average error
+ '35075': InvalidOrder, // Failed to cancel order
+ '35076': InvalidOrder, // LTC 20x leverage. Not allowed to open position
+ '35077': InvalidOrder, // Maximum 6 unfulfilled iceberg orders can be held at the same time
+ '35078': InvalidOrder, // Order amount exceeded 100,000
+ '35079': InvalidOrder, // Iceberg order price variance error
+ '35080': InvalidOrder, // Callback rate error
+ '35081': InvalidOrder, // Maximum 10 unfulfilled trail orders can be held at the same time
+ '35082': InvalidOrder, // Trail order callback rate error
+ '35083': InvalidOrder, // Each user can only hold a maximum of 10 unfulfilled stop-limit orders at the same time
+ '35084': InvalidOrder, // Order amount exceeded 1 million
+ '35085': InvalidOrder, // Order amount is not in the correct range
+ '35086': InvalidOrder, // Price exceeds 100 thousand
+ '35087': InvalidOrder, // Price exceeds 100 thousand
+ '35088': InvalidOrder, // Average amount error
+ '35089': InvalidOrder, // Price exceeds 100 thousand
+ '35090': ExchangeError, // No stop-limit orders available for cancelation
+ '35091': ExchangeError, // No trail orders available for cancellation
+ '35092': ExchangeError, // No iceberg orders available for cancellation
+ '35093': ExchangeError, // No trail orders available for cancellation
+ '35094': ExchangeError, // Stop-limit order last traded price error
+ '35095': BadRequest, // Instrument_id error
+ '35096': ExchangeError, // Algo order status error
+ '35097': ExchangeError, // Order status and order ID cannot exist at the same time
+ '35098': ExchangeError, // An order status or order ID must exist
+ '35099': ExchangeError, // Algo order ID error
+ // option
+ '36001': BadRequest, // Invalid underlying index.
+ '36002': BadRequest, // Instrument does not exist.
+ '36005': ExchangeError, // Instrument status is invalid.
+ '36101': AuthenticationError, // Account does not exist.
+ '36102': PermissionDenied, // Account status is invalid.
+ '36103': AccountSuspended, // Account is suspended due to ongoing liquidation.
+ '36104': PermissionDenied, // Account is not enabled for options trading.
+ '36105': PermissionDenied, // Please enable the account for option contract.
+ '36106': AccountSuspended, // Funds cannot be transferred in or out, as account is suspended.
+ '36107': PermissionDenied, // Funds cannot be transferred out within 30 minutes after option exercising or settlement.
+ '36108': InsufficientFunds, // Funds cannot be transferred in or out, as equity of the account is less than zero.
+ '36109': PermissionDenied, // Funds cannot be transferred in or out during option exercising or settlement.
+ '36201': PermissionDenied, // New order function is blocked.
+ '36202': PermissionDenied, // Account does not have permission to short option.
+ '36203': InvalidOrder, // Invalid format for client_oid.
+ '36204': ExchangeError, // Invalid format for request_id.
+ '36205': BadRequest, // Instrument id does not match underlying index.
+ '36206': BadRequest, // Order_id and client_oid can not be used at the same time.
+ '36207': InvalidOrder, // Either order price or fartouch price must be present.
+ '36208': InvalidOrder, // Either order price or size must be present.
+ '36209': InvalidOrder, // Either order_id or client_oid must be present.
+ '36210': InvalidOrder, // Either order_ids or client_oids must be present.
+ '36211': InvalidOrder, // Exceeding max batch size for order submission.
+ '36212': InvalidOrder, // Exceeding max batch size for oder cancellation.
+ '36213': InvalidOrder, // Exceeding max batch size for order amendment.
+ '36214': ExchangeError, // Instrument does not have valid bid/ask quote.
+ '36216': OrderNotFound, // Order does not exist.
+ '36217': InvalidOrder, // Order submission failed.
+ '36218': InvalidOrder, // Order cancellation failed.
+ '36219': InvalidOrder, // Order amendment failed.
+ '36220': InvalidOrder, // Order is pending cancel.
+ '36221': InvalidOrder, // Order qty is not valid multiple of lot size.
+ '36222': InvalidOrder, // Order price is breaching highest buy limit.
+ '36223': InvalidOrder, // Order price is breaching lowest sell limit.
+ '36224': InvalidOrder, // Exceeding max order size.
+ '36225': InvalidOrder, // Exceeding max open order count for instrument.
+ '36226': InvalidOrder, // Exceeding max open order count for underlying.
+ '36227': InvalidOrder, // Exceeding max open size across all orders for underlying
+ '36228': InvalidOrder, // Exceeding max available qty for instrument.
+ '36229': InvalidOrder, // Exceeding max available qty for underlying.
+ '36230': InvalidOrder, // Exceeding max position limit for underlying.
+ // --------------------------------------------------------
+ // swap
+ '400': BadRequest, // Bad Request
+ '401': AuthenticationError, // Unauthorized access
+ '403': PermissionDenied, // Access prohibited
+ '404': BadRequest, // Request address does not exist
+ '405': BadRequest, // The HTTP Method is not supported
+ '415': BadRequest, // The current media type is not supported
+ '429': DDoSProtection, // Too many requests
+ '500': ExchangeNotAvailable, // System busy
+ '1001': RateLimitExceeded, // The request is too frequent and has been throttled
+ '1002': ExchangeError, // {0} verifications within 24 hours
+ '1003': ExchangeError, // You failed more than {0} times today, the current operation is locked, please try again in 24 hours
+ // '00000': ExchangeError, // success
+ '40001': AuthenticationError, // ACCESS_KEY cannot be empty
+ '40002': AuthenticationError, // SECRET_KEY cannot be empty
+ '40003': AuthenticationError, // Signature cannot be empty
+ '40004': InvalidNonce, // Request timestamp expired
+ '40005': InvalidNonce, // Invalid ACCESS_TIMESTAMP
+ '40006': AuthenticationError, // Invalid ACCESS_KEY
+ '40007': BadRequest, // Invalid Content_Type
+ '40008': InvalidNonce, // Request timestamp expired
+ '40009': AuthenticationError, // sign signature error
+ '40010': AuthenticationError, // sign signature error
+ '40011': AuthenticationError, // ACCESS_PASSPHRASE cannot be empty
+ '40012': AuthenticationError, // apikey/password is incorrect
+ '40013': ExchangeError, // User status is abnormal
+ '40014': PermissionDenied, // Incorrect permissions
+ '40015': ExchangeError, // System is abnormal, please try again later
+ '40016': PermissionDenied, // The user must bind the phone or Google
+ '40017': ExchangeError, // Parameter verification failed
+ '40018': PermissionDenied, // Invalid IP
+ '40102': BadRequest, // Contract configuration does not exist, please check the parameters
+ '40103': BadRequest, // Request method cannot be empty
+ '40104': ExchangeError, // Lever adjustment failure
+ '40105': ExchangeError, // Abnormal access to current price limit data
+ '40106': ExchangeError, // Abnormal get next settlement time
+ '40107': ExchangeError, // Abnormal access to index price data
+ '40108': InvalidOrder, // Wrong order quantity
+ '40109': OrderNotFound, // The data of the order cannot be found, please confirm the order number
+ '40200': OnMaintenance, // Server upgrade, please try again later
+ '40201': InvalidOrder, // Order number cannot be empty
+ '40202': ExchangeError, // User information cannot be empty
+ '40203': BadRequest, // The amount of adjustment margin cannot be empty or negative
+ '40204': BadRequest, // Adjustment margin type cannot be empty
+ '40205': BadRequest, // Adjusted margin type data is wrong
+ '40206': BadRequest, // The direction of the adjustment margin cannot be empty
+ '40207': BadRequest, // The adjustment margin data is wrong
+ '40208': BadRequest, // The accuracy of the adjustment margin amount is incorrect
+ '40209': BadRequest, // The current page number is wrong, please confirm
+ '40300': ExchangeError, // User does not exist
+ '40301': PermissionDenied, // Permission has not been obtained yet. If you need to use it, please contact customer service
+ '40302': BadRequest, // Parameter abnormality
+ '40303': BadRequest, // Can only query up to 20,000 data
+ '40304': BadRequest, // Parameter type is abnormal
+ '40305': BadRequest, // Client_oid length is not greater than 50, and cannot be Martian characters
+ '40306': ExchangeError, // Batch processing orders can only process up to 20
+ '40308': OnMaintenance, // The contract is being temporarily maintained
+ '40309': BadSymbol, // The contract has been removed
+ '40400': ExchangeError, // Status check abnormal
+ '40401': ExchangeError, // The operation cannot be performed
+ '40402': BadRequest, // The opening direction cannot be empty
+ '40403': BadRequest, // Wrong opening direction format
+ '40404': BadRequest, // Whether to enable automatic margin call parameters cannot be empty
+ '40405': BadRequest, // Whether to enable the automatic margin call parameter type is wrong
+ '40406': BadRequest, // Whether to enable automatic margin call parameters is of unknown type
+ '40407': ExchangeError, // The query direction is not the direction entrusted by the plan
+ '40408': ExchangeError, // Wrong time range
+ '40409': ExchangeError, // Time format error
+ '40500': InvalidOrder, // Client_oid check error
+ '40501': ExchangeError, // Channel name error
+ '40502': ExchangeError, // If it is a copy user, you must pass the copy to whom
+ '40503': ExchangeError, // With the single type
+ '40504': ExchangeError, // Platform code must pass
+ '40505': ExchangeError, // Not the same as single type
+ '40506': AuthenticationError, // Platform signature error
+ '40507': AuthenticationError, // Api signature error
+ '40508': ExchangeError, // KOL is not authorized
+ '40509': ExchangeError, // Abnormal copy end
+ '40600': ExchangeError, // Copy function suspended
+ '40601': ExchangeError, // Followers cannot be KOL
+ '40602': ExchangeError, // The number of copies has reached the limit and cannot process the request
+ '40603': ExchangeError, // Abnormal copy end
+ '40604': ExchangeNotAvailable, // Server is busy, please try again later
+ '40605': ExchangeError, // Copy type, the copy number must be passed
+ '40606': ExchangeError, // The type of document number is wrong
+ '40607': ExchangeError, // Document number must be passed
+ '40608': ExchangeError, // No documented products currently supported
+ '40609': ExchangeError, // The contract product does not support copying
+ '40700': BadRequest, // Cursor parameters are incorrect
+ '40701': ExchangeError, // KOL is not authorized
+ '40702': ExchangeError, // Unauthorized copying user
+ '40703': ExchangeError, // Bill inquiry start and end time cannot be empty
+ '40704': ExchangeError, // Can only check the data of the last three months
+ '40705': BadRequest, // The start and end time cannot exceed 90 days
+ '40706': InvalidOrder, // Wrong order price
+ '40707': BadRequest, // Start time is greater than end time
+ '40708': BadRequest, // Parameter verification is abnormal
+ '40709': ExchangeError, // There is no position in this position, and no automatic margin call can be set
+ '40710': ExchangeError, // Abnormal account status
+ '40711': InsufficientFunds, // Insufficient contract account balance
+ '40712': InsufficientFunds, // Insufficient margin
+ '40713': ExchangeError, // Cannot exceed the maximum transferable margin amount
+ '40714': ExchangeError, // No direct margin call is allowed
+ // spot
+ 'invalid sign': AuthenticationError,
+ 'invalid currency': BadSymbol, // invalid trading pair
+ 'invalid symbol': BadSymbol,
+ 'invalid period': BadRequest, // invalid Kline type
+ 'invalid user': ExchangeError,
+ 'invalid amount': InvalidOrder,
+ 'invalid type': InvalidOrder, // {"status":"error","ts":1595700344504,"err_code":"invalid-parameter","err_msg":"invalid type"}
+ 'invalid orderId': InvalidOrder,
+ 'invalid record': ExchangeError,
+ 'invalid accountId': BadRequest,
+ 'invalid address': BadRequest,
+ 'accesskey not null': AuthenticationError, // {"status":"error","ts":1595704360508,"err_code":"invalid-parameter","err_msg":"accesskey not null"}
+ 'illegal accesskey': AuthenticationError,
+ 'sign not null': AuthenticationError,
+ 'req_time is too much difference from server time': InvalidNonce,
+ 'permissions not right': PermissionDenied, // {"status":"error","ts":1595704490084,"err_code":"invalid-parameter","err_msg":"permissions not right"}
+ 'illegal sign invalid': AuthenticationError, // {"status":"error","ts":1595684716042,"err_code":"invalid-parameter","err_msg":"illegal sign invalid"}
+ 'user locked': AccountSuspended,
+ 'Request Frequency Is Too High': RateLimitExceeded,
+ 'more than a daily rate of cash': BadRequest,
+ 'more than the maximum daily withdrawal amount': BadRequest,
+ 'need to bind email or mobile': ExchangeError,
+ 'user forbid': PermissionDenied,
+ 'User Prohibited Cash Withdrawal': PermissionDenied,
+ 'Cash Withdrawal Is Less Than The Minimum Value': BadRequest,
+ 'Cash Withdrawal Is More Than The Maximum Value': BadRequest,
+ 'the account with in 24 hours ban coin': PermissionDenied,
+ 'order cancel fail': BadRequest, // {"status":"error","ts":1595703343035,"err_code":"bad-request","err_msg":"order cancel fail"}
+ 'base symbol error': BadSymbol,
+ 'base date error': ExchangeError,
+ 'api signature not valid': AuthenticationError,
+ 'gateway internal error': ExchangeError,
+ 'audit failed': ExchangeError,
+ 'order queryorder invalid': BadRequest,
+ 'market no need price': InvalidOrder,
+ 'limit need price': InvalidOrder,
+ 'userid not equal to account_id': ExchangeError,
+ 'your balance is low': InsufficientFunds, // {"status":"error","ts":1595594160149,"err_code":"invalid-parameter","err_msg":"invalid size, valid range: [1,2000]"}
+ 'address invalid cointype': ExchangeError,
+ 'system exception': ExchangeError, // {"status":"error","ts":1595711862763,"err_code":"system exception","err_msg":"system exception"}
+ '50003': ExchangeError, // No record
+ '50004': BadSymbol, // The transaction pair is currently not supported or has been suspended
+ '50006': PermissionDenied, // The account is forbidden to withdraw. If you have any questions, please contact customer service.
+ '50007': PermissionDenied, // The account is forbidden to withdraw within 24 hours. If you have any questions, please contact customer service.
+ '50008': RequestTimeout, // network timeout
+ '50009': RateLimitExceeded, // The operation is too frequent, please try again later
+ '50010': ExchangeError, // The account is abnormally frozen. If you have any questions, please contact customer service.
+ '50014': InvalidOrder, // The transaction amount under minimum limits
+ '50015': InvalidOrder, // The transaction amount exceed maximum limits
+ '50016': InvalidOrder, // The price can't be higher than the current price
+ '50017': InvalidOrder, // Price under minimum limits
+ '50018': InvalidOrder, // The price exceed maximum limits
+ '50019': InvalidOrder, // The amount under minimum limits
+ '50020': InsufficientFunds, // Insufficient balance
+ '50021': InvalidOrder, // Price is under minimum limits
+ '50026': InvalidOrder, // Market price parameter error
+ 'invalid order query time': ExchangeError, // start time is greater than end time; or the time interval between start time and end time is greater than 48 hours
+ 'invalid start time': BadRequest, // start time is a date 30 days ago; or start time is a date in the future
+ 'invalid end time': BadRequest, // end time is a date 30 days ago; or end time is a date in the future
+ '20003': ExchangeError, // operation failed, {"status":"error","ts":1595730308979,"err_code":"bad-request","err_msg":"20003"}
+ '01001': ExchangeError, // order failed, {"status":"fail","err_code":"01001","err_msg":"系统异常,请稍后重试"}
+ },
+ 'broad': {
+ 'invalid size, valid range': ExchangeError,
+ },
+ },
+ 'precisionMode': TICK_SIZE,
+ 'options': {
+ 'createMarketBuyOrderRequiresPrice': true,
+ 'fetchMarkets': [
+ 'spot',
+ 'swap',
+ ],
+ 'parseOHLCV': {
+ 'volume': {
+ 'spot': 'amount',
+ 'swap': 5,
+ },
+ },
+ 'defaultType': 'spot', // 'spot', 'swap'
+ 'accountId': undefined, // '1012838157',
+ 'timeframes': {
+ 'spot': {
+ '1m': '1min',
+ '5m': '5min',
+ '15m': '15min',
+ '30m': '30min',
+ '1h': '60min',
+ '2h': '120min',
+ '4h': '240min',
+ '6h': '360min',
+ '12h': '720min',
+ '1d': '1day',
+ '1w': '1week',
+ },
+ 'swap': {
+ '1m': '60',
+ '5m': '300',
+ '15m': '900',
+ '30m': '1800',
+ '1h': '3600',
+ '2h': '7200',
+ '4h': '14400',
+ '6h': '21600',
+ '12h': '43200',
+ '1d': '86400',
+ '1w': '604800',
+ },
+ },
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.dataGetCommonTimestamp (params);
+ //
+ // {
+ // "status":"ok",
+ // "data":"1595525139400"
+ // }
+ //
+ return this.safeInteger (response, 'data');
+ }
+
+ async fetchMarkets (params = {}) {
+ let types = this.safeValue (this.options, 'fetchMarkets');
+ if (!types.length) {
+ types = [
+ this.options['defaultType'],
+ ];
+ }
+ let result = [];
+ for (let i = 0; i < types.length; i++) {
+ const markets = await this.fetchMarketsByType (types[i], params);
+ result = this.arrayConcat (result, markets);
+ }
+ return result;
+ }
+
+ parseMarkets (markets) {
+ const result = [];
+ for (let i = 0; i < markets.length; i++) {
+ result.push (this.parseMarket (markets[i]));
+ }
+ return result;
+ }
+
+ parseMarket (market) {
+ //
+ // spot
+ //
+ // {
+ // "base_currency":"btc",
+ // "quote_currency":"usdt",
+ // "symbol":"btc_usdt",
+ // "tick_size":"2",
+ // "size_increment":"4",
+ // "status":"1",
+ // "base_asset_precision":"8"
+ // }
+ //
+ //
+ // swap
+ //
+ // {
+ // "symbol":"btcusd",
+ // "underlying_index":"BTC",
+ // "quote_currency":"USD",
+ // "coin":"BTC",
+ // "contract_val":"1",
+ // "listing":null,
+ // "delivery":["07:00:00","15:00:00","23:00:00"],
+ // "size_increment":"0",
+ // "tick_size":"1",
+ // "forwardContractFlag":false,
+ // "priceEndStep":5
+ // }
+ //
+ const id = this.safeString (market, 'symbol');
+ let marketType = 'spot';
+ let spot = true;
+ let swap = false;
+ const baseId = this.safeString2 (market, 'base_currency', 'coin');
+ const quoteId = this.safeString (market, 'quote_currency');
+ const contractVal = this.safeFloat (market, 'contract_val');
+ if (contractVal !== undefined) {
+ marketType = 'swap';
+ spot = false;
+ swap = true;
+ }
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ let symbol = id.toUpperCase ();
+ if (spot) {
+ symbol = base + '/' + quote;
+ }
+ const tickSize = this.safeString (market, 'tick_size');
+ const sizeIncrement = this.safeString (market, 'size_increment');
+ const precision = {
+ 'amount': parseFloat ('1e-' + sizeIncrement),
+ 'price': parseFloat ('1e-' + tickSize),
+ };
+ const minAmount = this.safeFloat2 (market, 'min_size', 'base_min_size');
+ const status = this.safeString (market, 'status');
+ let active = undefined;
+ if (status !== undefined) {
+ active = (status === '1');
+ }
+ const fees = this.safeValue2 (this.fees, marketType, 'trading', {});
+ return this.extend (fees, {
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'info': market,
+ 'type': marketType,
+ 'spot': spot,
+ 'swap': swap,
+ 'active': active,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': minAmount,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': precision['price'],
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': precision['price'],
+ 'max': undefined,
+ },
+ },
+ });
+ }
+
+ async fetchMarketsByType (type, params = {}) {
+ if (type === 'spot') {
+ const response = await this.dataGetCommonSymbols (params);
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595526622408,
+ // "data":[
+ // {
+ // "base_currency":"btc",
+ // "quote_currency":"usdt",
+ // "symbol":"btc_usdt",
+ // "tick_size":"2",
+ // "size_increment":"4",
+ // "status":"1",
+ // "base_asset_precision":"8"
+ // },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseMarkets (data);
+ } else if (type === 'swap') {
+ const response = await this.capiGetMarketContracts (params);
+ //
+ // {
+ // "data":{
+ // "contractApis":[
+ // {
+ // "instrument_id":"btcusd",
+ // "underlying_index":"BTC",
+ // "quote_currency":"USD",
+ // "coin":"BTC",
+ // "contract_val":"1",
+ // "delivery":["07:00:00","15:00:00","23:00:00"],
+ // "size_increment":"0",
+ // "tick_size":"1",
+ // "forwardContractFlag":false,
+ // "priceEndStep":"5"
+ // },
+ // ]
+ // },
+ // "status":"ok",
+ // "err_code":"00000"
+ // }
+ //
+ return this.parseMarkets (response);
+ } else {
+ throw new NotSupported (this.id + ' fetchMarketsByType does not support market type ' + type);
+ }
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.dataGetCommonCurrencys (params);
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595537740466,
+ // "data":[
+ // "btc",
+ // "bft",
+ // "usdt",
+ // "usdt-omni",
+ // "usdt-erc20"
+ // ]
+ // }
+ //
+ const result = {};
+ const data = this.safeValue (response, 'data', []);
+ for (let i = 0; i < data.length; i++) {
+ const id = data[i];
+ const code = this.safeCurrencyCode (id);
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': id,
+ 'type': undefined,
+ 'name': undefined,
+ 'active': undefined,
+ 'fee': undefined,
+ 'precision': undefined,
+ 'limits': {
+ 'amount': { 'min': undefined, 'max': undefined },
+ 'price': { 'min': undefined, 'max': undefined },
+ 'cost': { 'min': undefined, 'max': undefined },
+ 'withdraw': { 'min': undefined, 'max': undefined },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ if (market['spot']) {
+ method = 'dataGetMarketDepth';
+ request['type'] = 'step0'; // step0, step1, step2, step3, step4, step5, do not merge depth if step0
+ } else if (market['swap']) {
+ method = 'capiGetMarketDepth';
+ request['limit'] = (limit === undefined) ? 100 : limit; // max 100
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ch":"market.btc_usdt.depth.step0",
+ // "ts":1595607628197,
+ // "data":{
+ // "id":"1595607628197",
+ // "ts":"1595607628197",
+ // "bids":[
+ // ["9534.99","15.36160000000000000000"],
+ // ["9534.85","0.14580000000000000000"],
+ // ["9534.73","0.02100000000000000000"],
+ // ],
+ // "asks":[
+ // ["9535.02","7.37160000000000000000"],
+ // ["9535.03","0.09040000000000000000"],
+ // ["9535.05","0.02180000000000000000"],
+ // ]
+ // }
+ // }
+ //
+ // swap
+ //
+ // {
+ // "asks":[
+ // ["9579.0","119865",1],
+ // ["9579.5","90069",1],
+ // ["9580.0","256673",1],
+ // ],
+ // "bids":[
+ // ["9578.5","2417",1],
+ // ["9577.5","3024",1],
+ // ["9577.0","21548",1],
+ // ],
+ // "timestamp":"1595664767349"
+ // }
+ //
+ const data = this.safeValue (response, 'data', response);
+ const timestamp = this.safeInteger2 (data, 'timestamp', 'ts');
+ const nonce = this.safeInteger (data, 'id');
+ const orderbook = this.parseOrderBook (data, timestamp);
+ orderbook['nonce'] = nonce;
+ return orderbook;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // spot
+ //
+ // fetchTicker
+ //
+ // {
+ // "id":"1595538241113",
+ // "bid":["0.028474000000","1.139400000000"],
+ // "ask":["0.028482000000","0.353100000000"],
+ // "amount":"2850.6649",
+ // "count":"818",
+ // "open":"0.02821",
+ // "close":"0.028474",
+ // "low":"0.02821",
+ // "high":"0.029091",
+ // "vol":"79.4548693404"
+ // }
+ //
+ // fetchTickers
+ //
+ // {
+ // "amount":"30086.8095",
+ // "count":"22450",
+ // "open":"9525.11",
+ // "close":"9591.81",
+ // "low":"9510.68",
+ // "high":"9659.7",
+ // "vol":"286239092.250461",
+ // "symbol":"btc_usdt"
+ // }
+ //
+ // swap
+ //
+ // {
+ // "instrument_id":"btcusd",
+ // "last":"9574.5",
+ // "best_ask":"9575.0",
+ // "best_bid":"9574.0",
+ // "high_24h":"9672",
+ // "low_24h":"9512",
+ // "volume_24h":"567697050",
+ // "timestamp":"1595538450096"
+ // }
+ //
+ const timestamp = this.safeInteger2 (ticker, 'timestamp', 'id');
+ let symbol = undefined;
+ const marketId = this.safeString2 (ticker, 'instrument_id', 'symbol');
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ symbol = market['symbol'];
+ } else if (marketId !== undefined) {
+ const parts = marketId.split ('_');
+ const numParts = parts.length;
+ if (numParts === 2) {
+ const [ baseId, quoteId ] = parts;
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ } else {
+ symbol = marketId;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ const last = this.safeFloat2 (ticker, 'last', 'close');
+ const open = this.safeFloat (ticker, 'open');
+ let bidVolume = undefined;
+ let askVolume = undefined;
+ let bid = this.safeValue (ticker, 'bid');
+ if (bid === undefined) {
+ bid = this.safeFloat (ticker, 'best_bid');
+ } else {
+ bidVolume = this.safeFloat (bid, 1);
+ bid = this.safeFloat (bid, 0);
+ }
+ let ask = this.safeValue (ticker, 'ask');
+ if (ask === undefined) {
+ ask = this.safeFloat (ticker, 'best_ask');
+ } else {
+ askVolume = this.safeFloat (ask, 1);
+ ask = this.safeFloat (ask, 0);
+ }
+ const baseVolume = this.safeFloat2 (ticker, 'amount', 'volume_24h');
+ const quoteVolume = this.safeFloat (ticker, 'vol');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ let change = undefined;
+ let percentage = undefined;
+ let average = undefined;
+ if ((last !== undefined) && (open !== undefined)) {
+ change = last - open;
+ percentage = change / open * 100;
+ average = this.sum (open, last) / 2;
+ }
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat2 (ticker, 'high', 'high_24h'),
+ 'low': this.safeFloat2 (ticker, 'low', 'low_24h'),
+ 'bid': bid,
+ 'bidVolume': bidVolume,
+ 'ask': ask,
+ 'askVolume': askVolume,
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ let method = undefined;
+ if (market['spot']) {
+ method = 'dataGetMarketDetailMerged';
+ } else if (market['swap']) {
+ method = 'capiGetMarketTicker';
+ }
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ch":"market.eth_btc.detail.merged",
+ // "ts":1595538241474,
+ // "data":{
+ // "id":"1595538241113",
+ // "bid":["0.028474000000","1.139400000000"],
+ // "ask":["0.028482000000","0.353100000000"],
+ // "amount":"2850.6649",
+ // "count":"818",
+ // "open":"0.02821",
+ // "close":"0.028474",
+ // "low":"0.02821",
+ // "high":"0.029091",
+ // "vol":"79.4548693404"
+ // }
+ // }
+ //
+ // swap
+ //
+ // {
+ // "symbol":"btcusd",
+ // "last":"9575.5",
+ // "best_ask":"9576.0",
+ // "best_bid":"9575.0",
+ // "high_24h":"9646",
+ // "low_24h":"9516",
+ // "volume_24h":"516656839",
+ // "timestamp":"1595664217405"
+ // }
+ //
+ const data = this.safeValue (response, 'data', response);
+ return this.parseTicker (data, market);
+ }
+
+ async fetchTickersByType (type, symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ let method = undefined;
+ if (type === 'spot') {
+ method = 'dataGetMarketTickers';
+ } else if (type === 'swap') {
+ method = 'capiGetMarketTickers';
+ }
+ const response = await this[method] (params);
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595542893250,
+ // "data":[
+ // {
+ // "amount":"30086.8095",
+ // "count":"22450",
+ // "open":"9525.11",
+ // "close":"9591.81",
+ // "low":"9510.68",
+ // "high":"9659.7",
+ // "vol":"286239092.250461",
+ // "symbol":"btc_usdt"
+ // }
+ // ]
+ // }
+ //
+ // swap
+ //
+ // [
+ // {
+ // "symbol":"btcusd",
+ // "last":"9572",
+ // "best_ask":"9571.5",
+ // "best_bid":"9570.5",
+ // "high_24h":"9646",
+ // "low_24h":"9516",
+ // "volume_24h":"515401635",
+ // "timestamp":"1595664479952"
+ // }
+ // ]
+ //
+ const data = this.safeValue (response, 'data', response);
+ let timestamp = undefined;
+ if (!Array.isArray (response)) {
+ timestamp = this.safeInteger (response, 'ts');
+ }
+ const result = {};
+ for (let i = 0; i < data.length; i++) {
+ const ticker = this.parseTicker (this.extend ({
+ 'timestamp': timestamp,
+ }, data[i]));
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ const defaultType = this.safeString2 (this.options, 'fetchTickers', 'defaultType');
+ const type = this.safeString (params, 'type', defaultType);
+ return await this.fetchTickersByType (type, symbols, this.omit (params, 'type'));
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // spot
+ //
+ // {
+ // "id":"1",
+ // "price":"9533.81",
+ // "amount":"0.7326",
+ // "direction":"sell",
+ // "ts":"1595604964000"
+ // }
+ //
+ // swap
+ //
+ // {
+ // "trade_id":"670581881367954915",
+ // "price":"9553.00",
+ // "size":"20",
+ // "side":"sell",
+ // "timestamp":"1595605100004",
+ // "symbol":"btcusd"
+ // }
+ //
+ // spot fetchMyTrades (private)
+ //
+ // {
+ // "id": 29555,
+ // "order_id": 59378,
+ // "match_id": 59335,
+ // "symbol": "eth_usdt",
+ // "type": "buy-limit",
+ // "source": "api",
+ // "price": "100.1000000000",
+ // "filled_amount": "0.9845000000",
+ // "filled_fees": "0.0019690000",
+ // "created_at": 1494901400487
+ // }
+ //
+ // fetchOrderTrades (private)
+ //
+ // spot
+ //
+ // {
+ // "id":"614164775",
+ // "created_at":"1596298860602",
+ // "filled_amount":"0.0417000000000000",
+ // "filled_fees":"0.0000834000000000",
+ // "match_id":"673491702661292033",
+ // "order_id":"673491720340279296",
+ // "price":"359.240000000000",
+ // "source":"接口",
+ // "symbol":"eth_usdt",
+ // "type":"buy-market"
+ // }
+ //
+ // swap
+ //
+ // {
+ // "trade_id":"6667390",
+ // "symbol":"cmt_btcusdt",
+ // "order_id":"525946425993854915",
+ // "price":"9839.00",
+ // "order_qty":"3466",
+ // "fee":"-0.0000528407360000",
+ // "timestamp":"1561121514442",
+ // "exec_type":"M",
+ // "side":"3"
+ // }
+ //
+ let symbol = undefined;
+ const marketId = this.safeString (trade, 'symbol');
+ let base = undefined;
+ let quote = undefined;
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ symbol = market['symbol'];
+ base = market['base'];
+ quote = market['quote'];
+ } else if (marketId !== undefined) {
+ const parts = marketId.split ('_');
+ const numParts = parts.length;
+ if (numParts === 2) {
+ const [ baseId, quoteId ] = parts;
+ base = this.safeCurrencyCode (baseId);
+ quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ } else {
+ symbol = marketId.toUpperCase ();
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ base = market['base'];
+ quote = market['quote'];
+ }
+ let timestamp = this.safeInteger (trade, 'created_at');
+ timestamp = this.safeInteger2 (trade, 'timestamp', 'ts', timestamp);
+ const price = this.safeFloat (trade, 'price');
+ let amount = this.safeFloat2 (trade, 'filled_amount', 'order_qty');
+ amount = this.safeFloat2 (trade, 'size', 'amount', amount);
+ let takerOrMaker = this.safeString2 (trade, 'exec_type', 'liquidity');
+ if (takerOrMaker === 'M') {
+ takerOrMaker = 'maker';
+ } else if (takerOrMaker === 'T') {
+ takerOrMaker = 'taker';
+ }
+ const orderType = this.safeString (trade, 'type');
+ let side = undefined;
+ let type = undefined;
+ if (orderType !== undefined) {
+ side = this.safeString (trade, 'type');
+ type = this.parseOrderType (side);
+ side = this.parseOrderSide (side);
+ } else {
+ side = this.safeString2 (trade, 'side', 'direction');
+ type = this.parseOrderType (side);
+ side = this.parseOrderSide (side);
+ }
+ let cost = undefined;
+ if (amount !== undefined) {
+ if (price !== undefined) {
+ cost = amount * price;
+ }
+ }
+ let feeCost = this.safeFloat (trade, 'fee');
+ if (feeCost === undefined) {
+ feeCost = this.safeFloat (trade, 'filled_fees');
+ } else {
+ feeCost = -feeCost;
+ }
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrency = (side === 'buy') ? base : quote;
+ fee = {
+ // fee is either a positive number (invitation rebate)
+ // or a negative number (transaction fee deduction)
+ // therefore we need to invert the fee
+ // more about it https://github.com/ccxt/ccxt/issues/5909
+ 'cost': feeCost,
+ 'currency': feeCurrency,
+ };
+ }
+ const orderId = this.safeString (trade, 'order_id');
+ const id = this.safeString2 (trade, 'trade_id', 'id');
+ return {
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'id': id,
+ 'order': orderId,
+ 'type': type,
+ 'takerOrMaker': takerOrMaker,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTrades (symbol, limit = undefined, since = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ if (market['spot']) {
+ method = 'dataGetMarketHistoryTrade';
+ } else if (market['swap']) {
+ method = 'capiGetMarketTrades';
+ }
+ if (market['spot']) {
+ if (limit !== undefined) {
+ request['size'] = limit; // default 1, max 2000
+ }
+ } else if (market['swap']) {
+ if (limit === undefined) {
+ limit = 100; // default 20, max 100
+ }
+ request['limit'] = limit;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ch":"market.btc_usdt.trade.detail",
+ // "ts":1595604968430,
+ // "data":{
+ // "ts":"1595604964000",
+ // "data":[
+ // {"id":"1","price":"9533.81","amount":"0.7326","direction":"sell","ts":"1595604964000"},
+ // {"id":"2","price":"9533.67","amount":"1.1591","direction":"buy","ts":"1595604961000"},
+ // {"id":"3","price":"9533.67","amount":"1.5022","direction":"sell","ts":"1595604959000"},
+ // ]
+ // }
+ // }
+ //
+ // swap
+ //
+ // [
+ // {"trade_id":"670833198971748613","price":"9578.50","size":"5412","side":"sell","timestamp":"1595665018790","symbol":"btcusd"},
+ // {"trade_id":"670833194240574915","price":"9579.00","size":"3972","side":"buy","timestamp":"1595665017662","symbol":"btcusd"},
+ // {"trade_id":"670833194240573915","price":"9579.00","size":"1227","side":"buy","timestamp":"1595665017662","symbol":"btcusd"},
+ // ]
+ //
+ let trades = undefined;
+ if (Array.isArray (response)) {
+ trades = response;
+ } else {
+ const data = this.safeValue (response, 'data', {});
+ trades = this.safeValue2 (data, 'data', []);
+ }
+ return this.parseTrades (trades, market, since, limit);
+ }
+
+ parseOHLCV (ohlcv, market = undefined, timeframe = '1m') {
+ //
+ // spot
+ //
+ // {
+ // "id":"1594694700000",
+ // "amount":"283.6811",
+ // "count":"234",
+ // "open":"9230.00",
+ // "close":"9227.15",
+ // "low":"9206.66",
+ // "high":"9232.33",
+ // "vol":"2618015.032504000000"
+ // }
+ //
+ // swap
+ //
+ // [
+ // "1594693800000",
+ // "9240",
+ // "9241",
+ // "9222",
+ // "9228.5",
+ // "3913370",
+ // "424.003616350563"
+ // ]
+ //
+ const options = this.safeValue (this.options, 'parseOHLCV', {});
+ const volume = this.safeValue (options, 'volume', {});
+ if (Array.isArray (ohlcv)) {
+ const volumeIndex = this.safeString (volume, market['type'], 'amount');
+ return [
+ this.safeInteger (ohlcv, 0), // timestamp
+ this.safeFloat (ohlcv, 1), // Open
+ this.safeFloat (ohlcv, 2), // High
+ this.safeFloat (ohlcv, 3), // Low
+ this.safeFloat (ohlcv, 4), // Close
+ // this.safeFloat (ohlcv, 5), // Quote Volume
+ // this.safeFloat (ohlcv, 6), // Base Volume
+ this.safeFloat (ohlcv, volumeIndex), // Volume, bitget will return base volume in the 7th element for future markets
+ ];
+ } else {
+ const volumeIndex = this.safeValue (volume, market['type'], 6);
+ return [
+ this.safeInteger (ohlcv, 'id'),
+ this.safeFloat (ohlcv, 'open'), // Open
+ this.safeFloat (ohlcv, 'high'), // High
+ this.safeFloat (ohlcv, 'low'), // Low
+ this.safeFloat (ohlcv, 'close'), // Close
+ this.safeFloat (ohlcv, volumeIndex), // Base Volume
+ ];
+ }
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ const type = market['type'];
+ const options = this.safeValue (this.options, 'timeframes', {});
+ const intervals = this.safeValue (options, type, {});
+ const interval = this.safeValue (intervals, this.timeframes[timeframe]);
+ if (market['spot']) {
+ method = 'dataGetMarketHistoryKline';
+ request['period'] = interval;
+ if (limit !== undefined) {
+ request['size'] = limit; // default 150, max 1000
+ }
+ } else if (market['swap']) {
+ const duration = this.parseTimeframe (timeframe);
+ method = 'capiGetMarketCandles';
+ request['granularity'] = interval;
+ const now = this.milliseconds ();
+ if (since === undefined) {
+ if (limit === undefined) {
+ limit = 1000;
+ }
+ request['start'] = this.iso8601 (now - limit * duration * 1000);
+ request['end'] = this.iso8601 (now);
+ } else {
+ request['start'] = this.iso8601 (since);
+ if (limit === undefined) {
+ request['end'] = this.iso8601 (now);
+ } else {
+ request['end'] = this.iso8601 (this.sum (since, limit * duration * 1000));
+ }
+ }
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ch":"market.btc_usdt.kline.15min",
+ // "ts":1595594183874,
+ // "data":[
+ // {"id":"1594694700000","amount":"283.6811","count":"234","open":"9230.00","close":"9227.15","low":"9206.66","high":"9232.33","vol":"2618015.032504000000"},
+ // {"id":"1594695600000","amount":"457.2904","count":"238","open":"9227.15","close":"9229.46","low":"9223.80","high":"9235.14","vol":"4220734.684570000000"},
+ // {"id":"1594696500000","amount":"501.2353","count":"255","open":"9229.46","close":"9227.78","low":"9222.69","high":"9230.74","vol":"4625779.185006000000"},
+ // ]
+ // }
+ //
+ // swap
+ //
+ // [
+ // ["1594764900000","9255.5","9261","9251","9255.5","3958946","427.742307964305"],
+ // ["1594765800000","9255.5","9264","9252","9258","3609496","389.832756058107"],
+ // ["1594766700000","9258","9260","9244.5","9250.5","3738600","403.97870345085"],
+ // ]
+ //
+ let candles = response;
+ if (!Array.isArray (response)) {
+ candles = this.safeValue (response, 'data', []);
+ }
+ return this.parseOHLCVs (candles, market, timeframe, since, limit);
+ }
+
+ parseSpotBalance (response) {
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595681450932,
+ // "data":{
+ // "list":[
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"trade"},
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"frozen"},
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"lock"},
+ // ],
+ // "id":"7420922606",
+ // "type":"spot",
+ // "state":"working"
+ // }
+ // }
+ //
+ const result = { 'info': response };
+ const data = this.safeValue (response, 'data');
+ const balances = this.safeValue (data, 'list');
+ for (let i = 0; i < balances.length; i++) {
+ const balance = balances[i];
+ const currencyId = this.safeString (balance, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ if (!(code in result)) {
+ const account = this.account ();
+ result[code] = account;
+ }
+ const type = this.safeValue (balance, 'type');
+ if (type === 'trade') {
+ result[code]['free'] = this.safeFloat (balance, 'balance');
+ } else if ((type === 'frozen') || (type === 'lock')) {
+ const used = this.safeFloat (result[code], 'used');
+ result[code]['used'] = this.sum (used, this.safeFloat (balance, 'balance'));
+ }
+ }
+ return this.parseBalance (result);
+ }
+
+ parseSwapBalance (response) {
+ //
+ // swap
+ //
+ // [
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"bchusd","margin_frozen":"0","timestamp":"1595673431547","margin_mode":"fixed","forwardContractFlag":false},
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"ethusd","margin_frozen":"0","timestamp":"1595673431573","margin_mode":"fixed","forwardContractFlag":false},
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"cmt_btcsusdt","margin_frozen":"0","timestamp":"1595673431577","margin_mode":"fixed","forwardContractFlag":true},
+ // ]
+ //
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const balance = response[i];
+ const marketId = this.safeString (balance, 'symbol');
+ let symbol = marketId;
+ if (marketId in this.markets_by_id) {
+ symbol = this.markets_by_id[marketId]['symbol'];
+ }
+ const account = this.account ();
+ // it may be incorrect to use total, free and used for swap accounts
+ account['total'] = this.safeFloat (balance, 'equity');
+ account['free'] = this.safeFloat (balance, 'total_avail_balance');
+ result[symbol] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchAccounts (params = {}) {
+ const request = {
+ 'method': 'accounts',
+ };
+ const response = await this.apiGetAccountAccounts (this.extend (request, params));
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595679591824,
+ // "data":[
+ // {"id":"7420922606","type":"spot","state":"working"}
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = [];
+ for (let i = 0; i < data.length; i++) {
+ const account = data[i];
+ const accountId = this.safeString (account, 'id');
+ const type = this.safeStringLower (account, 'type');
+ result.push ({
+ 'id': accountId,
+ 'type': type,
+ 'currency': undefined,
+ 'info': account,
+ });
+ }
+ return result;
+ }
+
+ async findAccountByType (type) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountsByType = this.groupBy (this.accounts, 'type');
+ const accounts = this.safeValue (accountsByType, type);
+ if (accounts === undefined) {
+ throw new ExchangeError (this.id + " findAccountByType() could not find an accountId with type '" + type + "', specify the 'accountId' parameter instead"); // eslint-disable-line quotes
+ }
+ const numAccounts = accounts.length;
+ if (numAccounts > 1) {
+ throw new ExchangeError (this.id + " findAccountByType() found more than one accountId with type '" + type + "', specify the 'accountId' parameter instead"); // eslint-disable-line quotes
+ }
+ return accounts[0];
+ }
+
+ async getAccountId (params) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const defaultAccountId = this.safeString (this.options, 'accountId');
+ const accountId = this.safeString (params, 'accountId', defaultAccountId);
+ if (accountId !== undefined) {
+ return accountId;
+ }
+ const defaultType = this.safeString (this.options, 'defaultType', 'margin');
+ const type = this.safeString (params, 'type', defaultType);
+ params = this.omit (params, 'type');
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " requires an 'accountId' parameter");
+ }
+ const account = await this.findAccountByType (type);
+ return account['id'];
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType');
+ const type = this.safeString (params, 'type', defaultType);
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " fetchBalance requires a 'type' parameter, one of 'spot', 'swap'");
+ }
+ let method = undefined;
+ const query = this.omit (params, 'type');
+ if (type === 'spot') {
+ const accountId = await this.getAccountId (params);
+ method = 'apiGetAccountsAccountIdBalance';
+ query['account_id'] = accountId;
+ query['method'] = 'balance';
+ } else if (type === 'swap') {
+ method = 'swapGetAccountAccounts';
+ }
+ const response = await this[method] (query);
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595681450932,
+ // "data":{
+ // "list":[
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"trade"},
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"frozen"},
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"lock"},
+ // ],
+ // "id":"7420922606",
+ // "type":"spot",
+ // "state":"working"
+ // }
+ // }
+ //
+ // swap
+ //
+ // [
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"bchusd","margin_frozen":"0","timestamp":"1595673431547","margin_mode":"fixed","forwardContractFlag":false},
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"ethusd","margin_frozen":"0","timestamp":"1595673431573","margin_mode":"fixed","forwardContractFlag":false},
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"cmt_btcsusdt","margin_frozen":"0","timestamp":"1595673431577","margin_mode":"fixed","forwardContractFlag":true},
+ // ]
+ //
+ return this.parseBalanceByType (type, response);
+ }
+
+ parseBalanceByType (type, response) {
+ if (type === 'spot') {
+ return this.parseSpotBalance (response);
+ } else if (type === 'swap') {
+ return this.parseSwapBalance (response);
+ }
+ throw new NotSupported (this.id + " fetchBalance does not support the '" + type + "' type (the type must be one of 'account', 'spot', 'margin', 'futures', 'swap')");
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'submitted': 'open',
+ 'partial-filled': 'open',
+ 'partial-canceled': 'canceled',
+ 'filled': 'closed',
+ 'canceled': 'canceled',
+ '-2': 'failed',
+ '-1': 'canceled',
+ '0': 'open',
+ '1': 'open',
+ '2': 'closed',
+ '3': 'open',
+ '4': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrderSide (side) {
+ const sides = {
+ 'buy-market': 'buy',
+ 'sell-market': 'sell',
+ 'buy-limit': 'buy',
+ 'sell-limit': 'sell',
+ '1': 'long', // open long
+ '2': 'short', // open short
+ '3': 'long', // close long
+ '4': 'short', // close short
+ };
+ return this.safeString (sides, side, side);
+ }
+
+ parseOrderType (type) {
+ const types = {
+ 'buy-market': 'market',
+ 'sell-market': 'market',
+ 'buy-limit': 'limit',
+ 'sell-limit': 'limit',
+ '1': 'open', // open long
+ '2': 'open', // open short
+ '3': 'close', // close long
+ '4': 'close', // close short
+ };
+ return this.safeString (types, type, type);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595792596056,
+ // "data":671368296142774272
+ // }
+ //
+ // swap
+ //
+ // {
+ // "client_oid":"58775e54-0592-491c-97e8-e2369025f2d1",
+ // "order_id":"671757564085534713"
+ // }
+ //
+ // cancelOrder
+ //
+ // spot
+ //
+ // {
+ // "status": "ok",
+ // "ts": 1595818631279,
+ // "data": 671368296142774272
+ // }
+ //
+ // swap
+ //
+ // {
+ // "order_id":"671757564085534713",
+ // "client_oid":"58775e54-0592-491c-97e8-e2369025f2d1",
+ // "symbol":"cmt_ethusdt",
+ // "result":true,
+ // "err_code":null,
+ // "err_msg":null
+ // }
+ //
+ // fetchOpenOrders, fetchClosedOrders, fetchOrder
+ //
+ // spot
+ //
+ // {
+ // "account_id":"7420922606",
+ // "amount":"0.1000000000000000",
+ // "canceled_at":"1595872129618",
+ // "created_at":"1595872089525",
+ // "filled_amount":"0.000000000000",
+ // "filled_cash_amount":"0.000000000000",
+ // "filled_fees":"0.000000000000",
+ // "finished_at":"1595872129618",
+ // "id":"671701716584665088",
+ // "price":"150.000000000000",
+ // "source":"接口",
+ // "state":"canceled",
+ // "symbol":"eth_usdt",
+ // "type":"buy-limit"
+ // }
+ //
+ // swap
+ //
+ // {
+ // "symbol":"cmt_ethusdt",
+ // "size":"1",
+ // "timestamp":"1595885546770",
+ // "client_oid":"f3aa81d6-9a4c-4eab-bebe-ebc19da21cf2",
+ // "createTime":"1595885521200",
+ // "filled_qty":"0",
+ // "fee":"0.00000000",
+ // "order_id":"671758053112020913",
+ // "price":"150.00",
+ // "price_avg":"0.00",
+ // "status":"0",
+ // "type":"1",
+ // "order_type":"0",
+ // "totalProfits":null
+ // }
+ //
+ let id = this.safeString (order, 'order_id');
+ id = this.safeString2 (order, 'id', 'data', id);
+ const timestamp = this.safeInteger2 (order, 'created_at', 'createTime');
+ let type = this.safeString (order, 'type');
+ const side = this.parseOrderSide (type);
+ type = this.parseOrderType (type);
+ // if ((side !== 'buy') && (side !== 'sell')) {
+ // side = this.parseOrderSide (type);
+ // }
+ // if ((type !== 'limit') && (type !== 'market')) {
+ // if ('pnl' in order) {
+ // type = 'futures';
+ // } else {
+ // type = 'swap';
+ // }
+ // }
+ let symbol = undefined;
+ const marketId = this.safeString (order, 'symbol');
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ symbol = marketId.toUpperCase ();
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ let amount = this.safeFloat2 (order, 'amount', 'size');
+ const filled = this.safeFloat2 (order, 'filled_amount', 'filled_qty');
+ let remaining = undefined;
+ if (amount !== undefined) {
+ if (filled !== undefined) {
+ amount = Math.max (amount, filled);
+ remaining = Math.max (0, amount - filled);
+ }
+ }
+ if (type === 'market') {
+ remaining = 0;
+ }
+ const cost = this.safeFloat (order, 'filled_cash_amount');
+ const price = this.safeFloat (order, 'price');
+ let average = this.safeFloat (order, 'price_avg');
+ if ((average === undefined) && (filled !== undefined) && (cost !== undefined) && (filled > 0)) {
+ average = cost / filled;
+ }
+ const status = this.parseOrderStatus (this.safeString2 (order, 'state', 'status'));
+ const feeCost = this.safeFloat2 (order, 'filled_fees', 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrency = undefined;
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrency,
+ };
+ }
+ const clientOrderId = this.safeString (order, 'client_oid');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'average': average,
+ 'cost': cost,
+ 'amount': amount,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': undefined,
+ };
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const market = this.market (symbol);
+ //
+ // spot
+ //
+ // account_id true string Account ID, obtained using the accounts method. Currency transactions use the accountid of the'spot' account; for loan asset transactions, please use the accountid of the'margin' account
+ // amount true string A limit order indicates the quantity of the order, when a market price buy order indicates how much money to buy, and when a market price sell order indicates how much currency to sell
+ // price false string Order price, market order does not pass this parameter
+ // source false string Order source api
+ // symbol true string Trading pair btc_usdt, eth_btc ...
+ // type true string Order Type buy-market: buy at market price, sell-market: sell at market price, buy-limit: buy at limit price, sell-limit: sell at limit price
+ //
+ // swap
+ //
+ // symbol String Yes Contract ID
+ // client_oid String Yes customize order IDs to identify your orders. (Less than 50 characters without special characters,
+ // size String Yes Quantity to buy or sell (value not equal to 0 or negative)
+ // type String Yes 1 Open long 2Open short 3 Close long 4 Close short
+ // order_type String Yes 0: Normal order (Unfilled and 0 imply normal limit order) 1: Post only 2: Fill or Kill 3: Immediate Or Cancel
+ // match_price String Yes 0 Limit price 1 market price
+ // price String No Price of each contract
+ //
+ const request = {
+ 'symbol': market['id'],
+ };
+ const clientOrderId = this.safeString2 (params, 'client_oid', 'clientOrderId', this.uuid ());
+ params = this.omit (params, [ 'client_oid', 'clientOrderId' ]);
+ let method = undefined;
+ if (market['spot']) {
+ const accountId = await this.getAccountId ({
+ 'type': market['type'],
+ });
+ method = 'apiPostOrderOrdersPlace';
+ request['account_id'] = accountId;
+ request['method'] = 'place';
+ request['type'] = side + '-' + type;
+ if (type === 'limit') {
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ request['price'] = this.priceToPrecision (symbol, price);
+ } else if (type === 'market') {
+ // for market buy it requires the amount of quote currency to spend
+ if (side === 'buy') {
+ let cost = this.safeFloat (params, 'amount');
+ const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true);
+ if (createMarketBuyOrderRequiresPrice) {
+ if (price !== undefined) {
+ if (cost === undefined) {
+ cost = amount * price;
+ }
+ } else if (cost === undefined) {
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument or in the 'amount' extra parameter (the exchange-specific behaviour)");
+ }
+ } else {
+ cost = (cost === undefined) ? amount : cost;
+ }
+ request['amount'] = this.costToPrecision (symbol, cost);
+ } else if (side === 'sell') {
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ }
+ }
+ // ...
+ } else if (market['swap']) {
+ request['order_type'] = '0'; // '0' = Normal order, undefined and 0 imply a normal limit order, '1' = Post only, '2' = Fill or Kill, '3' = Immediate Or Cancel
+ request['client_oid'] = clientOrderId;
+ const orderType = this.safeString (params, 'type');
+ if (orderType === undefined) {
+ throw new ArgumentsRequired (this.id + " createOrder requires a type parameter, '1' = open long, '2' = open short, '3' = close long, '4' = close short for " + market['type'] + ' orders');
+ }
+ request['size'] = this.amountToPrecision (symbol, amount);
+ request['type'] = orderType;
+ // if match_price is set to '1', the price parameter will be ignored for market orders
+ if (type === 'limit') {
+ request['match_price'] = '0';
+ request['price'] = this.priceToPrecision (symbol, price);
+ } else if (type === 'market') {
+ request['match_price'] = '1';
+ }
+ method = 'swapPostOrderPlaceOrder';
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595792596056,
+ // "data":"671368296142774272"
+ // }
+ //
+ // swap
+ //
+ // {
+ // "client_oid":"58775e54-0592-491c-97e8-e2369025f2d1",
+ // "order_id":"671757564085534713"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ let market = undefined;
+ let type = undefined;
+ if (symbol === undefined) {
+ const defaultType = this.safeString2 (this.options, 'cancelOrder', 'defaultType');
+ const type = this.safeString (params, 'type', defaultType);
+ if (type === 'spot') {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument for spot orders');
+ }
+ }
+ } else {
+ market = this.market (symbol);
+ type = market['type'];
+ }
+ const query = this.omit (params, 'type');
+ let method = undefined;
+ const request = {};
+ if (type === 'spot') {
+ method = 'apiPostOrderOrdersOrderIdSubmitcancel';
+ request['order_id'] = id;
+ request['method'] = 'submitcancel';
+ } else if (type === 'swap') {
+ method = 'swapPostOrderCancelOrder';
+ request['orderId'] = id;
+ request['symbol'] = market['id'];
+ }
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
+ //
+ // { "status": "ok", "ts": 1595818631279, "data": 671368296142774272 }
+ //
+ // swap
+ //
+ // {
+ // "order_id":"671757564085534713",
+ // "client_oid":"58775e54-0592-491c-97e8-e2369025f2d1",
+ // "symbol":"cmt_ethusdt",
+ // "result":true,
+ // "err_code":null,
+ // "err_msg":null
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrders (ids, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " cancelOrders requires a type parameter (one of 'spot', 'swap').");
+ }
+ const request = {};
+ let method = undefined;
+ if (type === 'spot') {
+ method = 'apiPostOrderOrdersBatchcancel';
+ request['method'] = 'batchcancel';
+ const jsonIds = this.json (ids);
+ const parts = jsonIds.split ('"');
+ request['order_ids'] = parts.join ('');
+ } else if (type === 'swap') {
+ method = 'swapPostOrderCancelBatchOrders';
+ request['symbol'] = market['id'];
+ request['ids'] = ids;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status": "ok",
+ // "data": {
+ // "success": [
+ // "673451224205135872",
+ // ],
+ // "failed": [
+ // {
+ // "err-msg": "invalid record",
+ // "order-id": "673451224205135873",
+ // "err-code": "base record invalid"
+ // }
+ // ]
+ // }
+ // }
+ //
+ // swap
+ //
+ // {
+ // "result":true,
+ // "symbol":"cmt_btcusdt",
+ // "order_ids":[
+ // "258414711",
+ // "478585558"
+ // ],
+ // "fail_infos":[
+ // {
+ // "order_id":"258414711",
+ // "err_code":"401",
+ // "err_msg":""
+ // }
+ // ]
+ // }
+ //
+ return response;
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " fetchOrder requires a type parameter (one of 'spot', 'swap').");
+ }
+ let method = undefined;
+ const request = {};
+ if (type === 'spot') {
+ const clientOid = this.safeString (params, 'client_oid');
+ if (clientOid !== undefined) {
+ method = 'apiPostOrderOrdersClientOid';
+ request['client_oid'] = clientOid;
+ } else {
+ method = 'apiPostOrderOrdersOrderId';
+ request['order_id'] = id;
+ }
+ request['method'] = 'getOrder';
+ } else if (type === 'swap') {
+ method = 'swapGetOrderDetail';
+ request['symbol'] = market['id'];
+ request['orderId'] = id;
+ }
+ const query = this.omit (params, 'type');
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595897886717,
+ // "data":{
+ // "account_id":"7420922606",
+ // "amount":"0.1000000000000000",
+ // "canceled_at":"1595818631541",
+ // "created_at":"1595792595897",
+ // "filled_amount":"0.000000000000",
+ // "filled_cash_amount":"0.000000000000",
+ // "filled_fees":"0.000000000000",
+ // "finished_at":"1595818631541",
+ // "id":"671368296142774272",
+ // "price":"150.000000000000",
+ // "source":"接口",
+ // "state":"canceled",
+ // "symbol":"eth_usdt",
+ // "type":"buy-limit"
+ // }
+ // }
+ //
+ //
+ // swap
+ //
+ // {
+ // "symbol":"cmt_ethusdt",
+ // "size":"1",
+ // "timestamp":"1595896459890",
+ // "client_oid":"58775e54-0592-491c-97e8-e2369025f2d1",
+ // "createTime":"1595885404607",
+ // "filled_qty":"0",
+ // "fee":"0",
+ // "order_id":"671757564085534713",
+ // "price":"150",
+ // "price_avg":"0",
+ // "status":"-1",
+ // "type":"1",
+ // "order_type":"0",
+ // "totalProfits":"0"
+ // }
+ //
+ const data = this.safeValue (response, 'data', response);
+ return this.parseOrder (data, market);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ if (type === 'spot') {
+ method = 'apiGetOrderOrdersOpenOrders';
+ // request['from'] = this.safeString (params, 'from'); // order id
+ // request['direct'] = 'next'; // or 'prev'
+ request['method'] = 'openOrders';
+ if (limit === undefined) {
+ request['size'] = limit; // default 100, max 1000
+ }
+ } else if (type === 'swap') {
+ method = 'swapGetOrderOrders';
+ request['status'] = '3'; // 0 Failed, 1 Partially Filled, 2 Fully Filled 3 = Open + Partially Filled, 4 Canceling
+ request['from'] = '1';
+ request['to'] = '1';
+ if (limit === undefined) {
+ request['limit'] = 100; // default 100, max 100
+ }
+ }
+ const query = this.omit (params, 'type');
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
+ //
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595875165865,
+ // "data":[
+ // {
+ // "account_id":"7420922606",
+ // "amount":"0.1000000000000000",
+ // "canceled_at":"1595872129618",
+ // "created_at":"1595872089525",
+ // "filled_amount":"0.000000000000",
+ // "filled_cash_amount":"0.000000000000",
+ // "filled_fees":"0.000000000000",
+ // "finished_at":"1595872129618",
+ // "id":"671701716584665088",
+ // "price":"150.000000000000",
+ // "source":"接口",
+ // "state":"canceled",
+ // "symbol":"eth_usdt",
+ // "type":"buy-limit"
+ // }
+ // ]
+ // }
+ //
+ // swap
+ //
+ // [
+ // {
+ // "symbol":"cmt_ethusdt",
+ // "size":"1",
+ // "timestamp":"1595885546770",
+ // "client_oid":"f3aa81d6-9a4c-4eab-bebe-ebc19da21cf2",
+ // "createTime":"1595885521200",
+ // "filled_qty":"0",
+ // "fee":"0.00000000",
+ // "order_id":"671758053112020913",
+ // "price":"150.00",
+ // "price_avg":"0.00",
+ // "status":"0",
+ // "type":"1",
+ // "order_type":"0",
+ // "totalProfits":null
+ // }
+ // ]
+ //
+ let data = response;
+ if (!Array.isArray (response)) {
+ data = this.safeValue (response, 'data', []);
+ }
+ return this.parseOrders (data, market, undefined, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchClosedOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ if (type === 'spot') {
+ method = 'apiGetOrderOrdersHistory';
+ // Value range [((end_time) – 48h), (end_time)]
+ // the query window is 48 hours at most
+ // the window shift range is the last 30 days
+ if (since !== undefined) {
+ request['start_time'] = since;
+ }
+ // request['end_time'] = this.safeInteger (params, 'end_time');
+ // request['from'] = this.safeString (params, 'from'); // order id
+ // request['direct'] = 'next'; // or 'prev'
+ request['method'] = 'openOrders';
+ if (limit === undefined) {
+ request['size'] = limit; // default 100, max 1000
+ }
+ } else if (type === 'swap') {
+ method = 'swapGetOrderOrders';
+ request['status'] = '2'; // 0 Failed, 1 Partially Filled, 2 Fully Filled 3 = Open + Partially Filled, 4 Canceling
+ request['from'] = '1';
+ request['to'] = '1';
+ if (limit === undefined) {
+ request['limit'] = 100; // default 100, max 100
+ }
+ }
+ const query = this.omit (params, 'type');
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
+ //
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595875165865,
+ // "data":[
+ // {
+ // "account_id":"7420922606",
+ // "amount":"0.1000000000000000",
+ // "canceled_at":"1595872129618",
+ // "created_at":"1595872089525",
+ // "filled_amount":"0.000000000000",
+ // "filled_cash_amount":"0.000000000000",
+ // "filled_fees":"0.000000000000",
+ // "finished_at":"1595872129618",
+ // "id":"671701716584665088",
+ // "price":"150.000000000000",
+ // "source":"接口",
+ // "state":"canceled",
+ // "symbol":"eth_usdt",
+ // "type":"buy-limit"
+ // }
+ // ]
+ // }
+ //
+ // swap
+ //
+ // [
+ // {
+ // "symbol":"cmt_ethusdt",
+ // "size":"1",
+ // "timestamp":"1595885546770",
+ // "client_oid":"f3aa81d6-9a4c-4eab-bebe-ebc19da21cf2",
+ // "createTime":"1595885521200",
+ // "filled_qty":"0",
+ // "fee":"0.00000000",
+ // "order_id":"671758053112020913",
+ // "price":"150.00",
+ // "price_avg":"0.00",
+ // "status":"0",
+ // "type":"1",
+ // "order_type":"0",
+ // "totalProfits":null
+ // }
+ // ]
+ //
+ let data = response;
+ if (!Array.isArray (response)) {
+ data = this.safeValue (response, 'data', []);
+ }
+ return this.parseOrders (data, market, undefined, limit);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchDeposits requires a currency code argument');
+ }
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ 'method': 'deposit_withdraw',
+ 'type': 'deposit',
+ 'size': 12,
+ };
+ const response = await this.apiGetOrderDepositWithdraw (this.extend (request, params));
+ //
+ // {
+ // "status": "ok",
+ // "data": [
+ // {
+ // "id": 1171,
+ // "type": "deposit",
+ // "currency": "usdt",
+ // "tx_hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
+ // "amount": 7.457467,
+ // "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
+ // "address_tag": "100040",
+ // "fee": 0,
+ // "state": "safe",
+ // "created_at": 1510912472199,
+ // "updated_at": 1511145876575
+ // },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTransactions (data, currency, since, limit, params);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchWithdrawals requires a currency code argument');
+ }
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ 'method': 'deposit_withdraw',
+ 'type': 'withdraw',
+ 'size': 12,
+ };
+ const response = await this.apiGetOrderDepositWithdraw (this.extend (request, params));
+ //
+ // {
+ // "status": "ok",
+ // "data": [
+ // {
+ // "id": 1171,
+ // "type": "withdraw",
+ // "currency": "usdt",
+ // "tx_hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
+ // "amount": 7.457467,
+ // "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
+ // "address_tag": "100040",
+ // "fee": 0,
+ // "state": "safe",
+ // "created_at": 1510912472199,
+ // "updated_at": 1511145876575
+ // },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTransactions (data, currency, since, limit, params);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ // withdrawals
+ 'WaitForOperation': 'pending', // 等待提现
+ 'OperationLock': 'pending', // 初审锁定成功
+ 'OperationSuccess': 'ok', // 提现成功
+ 'Cancel': 'canceled', // 用户撤销
+ 'Sure': 'ok', // 复审锁定成功
+ 'Fail': 'failed', // 出币异常
+ 'WaitForChainSure': 'ok', // 等待链上确认
+ // deposits
+ 'WAIT_0': 'pending', // 待确认
+ 'WAIT_1': 'pending', // 待确认
+ 'DATA_CHANGE': 'pending', // 待确认中
+ 'SUCCESS': 'ok', // 充值成功
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // fetchDeposits, fetchWithdrawals
+ //
+ // {
+ // "id": 1171,
+ // "type": "withdraw",
+ // "currency": "usdt",
+ // "tx_hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
+ // "amount": 7.457467,
+ // "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
+ // "address_tag": "100040",
+ // "fee": 0,
+ // "state": "safe",
+ // "created_at": 1510912472199,
+ // "updated_at": 1511145876575
+ // }
+ //
+ const id = this.safeString (transaction, 'id');
+ const address = this.safeString (transaction, 'address');
+ const tag = this.safeString (transaction, 'address_tag');
+ const tagFrom = undefined;
+ const tagTo = tag;
+ const addressFrom = undefined;
+ const addressTo = address;
+ let type = this.safeString (transaction, 'type');
+ if (type === 'withdraw') {
+ type = 'withdrawal';
+ } else if (type === 'deposit') {
+ type = 'deposit';
+ }
+ const currencyId = this.safeString (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const amount = this.safeFloat (transaction, 'amount');
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'state'));
+ const txid = this.safeString (transaction, 'tx_hash');
+ const timestamp = this.safeInteger (transaction, 'created_at');
+ const updated = this.safeInteger (transaction, 'updated_at');
+ const feeCost = this.safeFloat (transaction, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ fee = {
+ 'currency': code,
+ 'cost': feeCost,
+ };
+ }
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': code,
+ 'amount': amount,
+ 'addressFrom': addressFrom,
+ 'addressTo': addressTo,
+ 'address': address,
+ 'tagFrom': tagFrom,
+ 'tagTo': tagTo,
+ 'tag': tag,
+ 'status': status,
+ 'type': type,
+ 'updated': updated,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': fee,
+ };
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ const query = this.omit (params, 'type');
+ if (type === 'swap') {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades is not supported for ' + type + ' type');
+ }
+ //
+ // spot
+ //
+ // POST /api/v1/order/matchresults Query current order, order history
+ // symbol true string trading pair btc_usdt, eth_btc ...
+ // types false string Query order type combination buy-market, sell-market, buy-limit, sell-limit
+ // start_date false string Query start date, date format yyyy-mm-dd -61 days [-61day, end-date]
+ // end_date false string Query end date, date format yyyy-mm-dd Now [start-date, now]
+ // from false string Query start ID order record id
+ // direct false string Query direction ‘next’ is default , the transaction record ID is sorted from large to small prev,next
+ // size false string Query record size 100 <=100
+ //
+ const request = {
+ 'symbol': market['id'],
+ 'method': 'matchresults',
+ // 'types': 'buy-market,sell-market,buy-limit,sell-limit',
+ // 'start_date': this.ymd (since),
+ // 'end_date': this.ymd (this.milliseconds ()),
+ // 'size': 100,
+ // 'direct': 'next',
+ };
+ if (since !== undefined) {
+ request['start_date'] = this.ymd (since);
+ const end = this.sum (since, 2 * 24 * 60 * 60 * 1000);
+ request['end_date'] = this.ymd (end);
+ }
+ if (limit !== undefined) {
+ request['size'] = limit; // default 100, max 100
+ }
+ const response = await this.apiPostOrderMatchresults (this.extend (request, query));
+ //
+ // {
+ // "status": "ok",
+ // "data": [
+ // {
+ // "id": 29555,
+ // "order_id": 59378,
+ // "match_id": 59335,
+ // "symbol": "eth_usdt",
+ // "type": "buy-limit",
+ // "source": "api",
+ // "price": "100.1000000000",
+ // "filled_amount": "0.9845000000",
+ // "filled_fees": "0.0019690000",
+ // "created_at": 1494901400487
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrderTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ const query = this.omit (params, 'type');
+ let method = undefined;
+ const request = {};
+ if (type === 'spot') {
+ request['order_id'] = id;
+ request['method'] = 'matchresults';
+ method = 'apiPostOrderOrdersOrderIdMatchresults';
+ } else if (type === 'swap') {
+ request['orderId'] = id;
+ request['symbol'] = market['id'];
+ method = 'swapGetOrderFills';
+ }
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1596298917277,
+ // "data":[
+ // {
+ // "id":"614164775",
+ // "created_at":"1596298860602",
+ // "filled_amount":"0.0417000000000000",
+ // "filled_fees":"0.0000834000000000",
+ // "match_id":"673491702661292033",
+ // "order_id":"673491720340279296",
+ // "price":"359.240000000000",
+ // "source":"接口",
+ // "symbol":"eth_usdt",
+ // "type":"buy-market"
+ // }
+ // ]
+ // }
+ //
+ // swap
+ //
+ //
+ // [
+ // {
+ // "trade_id":"6667390",
+ // "symbol":"cmt_btcusdt",
+ // "order_id":"525946425993854915",
+ // "price":"9839.00",
+ // "order_qty":"3466",
+ // "fee":"-0.0000528407360000",
+ // "timestamp":"1561121514442",
+ // "exec_type":"M",
+ // "side":"3"
+ // }
+ // ]
+ //
+ let data = response;
+ if (!Array.isArray (data)) {
+ data = this.safeValue (response, 'data', []);
+ }
+ return await this.parseTrades (data, market, since, limit);
+ }
+
+ async fetchPosition (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this.swapGetPositionSinglePosition (this.extend (request, params));
+ //
+ // {
+ // "margin_mode":"fixed", // Margin mode: crossed / fixed
+ // "holding":[
+ // {
+ // "symbol":"cmt_btcusdt", // Contract name
+ // "liquidation_price":"0.00", // Estimated liquidation price
+ // "position":"0", // Position Margin, the margin for holding current positions
+ // "avail_position":"0", // Available position
+ // "avg_cost":"0.00", // Transaction average price
+ // "leverage":"2", // Leverage
+ // "realized_pnl":"0.00000000", // Realized Profit and loss
+ // "keepMarginRate":"0.005", // Maintenance margin rate
+ // "side":"1", // Position Direction Long or short, Mark obsolete
+ // "holdSide":"1", // Position Direction Long or short
+ // "timestamp":"1557571623963", // System timestamp
+ // "margin":"0.0000000000000000", // Used margin
+ // "unrealized_pnl":"0.00000000", // Unrealized profit and loss
+ // }
+ // ]
+ // }
+ return response;
+ }
+
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.swapGetPositionAllPosition (params);
+ //
+ // [
+ // {
+ // "margin_mode":"fixed",
+ // "holding":[
+ // {
+ // "liquidation_price":"0.00",
+ // "position":"0",
+ // "avail_position":"0",
+ // "avg_cost":"0.00",
+ // "symbol":"btcusd",
+ // "leverage":"20",
+ // "keepMarginRate":"0.005",
+ // "realized_pnl":"0.00000000",
+ // "unrealized_pnl":"0",
+ // "side":"long",
+ // "holdSide":"1",
+ // "timestamp":"1595698564915",
+ // "margin":"0.0000000000000000"
+ // },
+ // ]
+ // },
+ // ]
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let request = '/' + this.implodeParams (path, params);
+ if ((api === 'capi') || (api === 'swap')) {
+ request = '/api/swap/' + this.version + request;
+ } else {
+ request = '/' + api + '/v1' + request;
+ }
+ let query = this.omit (params, this.extractParams (path));
+ let url = this.implodeParams (this.urls['api'][api], { 'hostname': this.hostname }) + request;
+ if ((api === 'data') || (api === 'capi')) {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (api === 'swap') {
+ this.checkRequiredCredentials ();
+ const timestamp = this.milliseconds ().toString ();
+ let auth = timestamp + method + request;
+ if (method === 'POST') {
+ body = this.json (params);
+ auth += body;
+ } else {
+ if (Object.keys (params).length) {
+ const query = this.urlencode (this.keysort (params));
+ url += '?' + query;
+ auth += '?' + query;
+ }
+ }
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256', 'base64');
+ headers = {
+ 'ACCESS-KEY': this.apiKey,
+ 'ACCESS-SIGN': signature,
+ 'ACCESS-TIMESTAMP': timestamp,
+ 'ACCESS-PASSPHRASE': this.password,
+ };
+ if (method === 'POST') {
+ headers['Content-Type'] = 'application/json';
+ }
+ } else if (api === 'api') {
+ const timestamp = this.milliseconds ().toString ();
+ let auth = '';
+ query = this.keysort (query);
+ auth = this.rawencode (query);
+ const hash = this.hash (this.encode (this.secret), 'sha1');
+ let signed = auth;
+ const signature = this.hmac (this.encode (auth), this.encode (hash), 'md5');
+ if (auth.length > 0) {
+ signed += '&';
+ }
+ signed += 'sign=' + signature + '&req_time=' + timestamp + '&accesskey=' + this.apiKey;
+ if (method === 'GET') {
+ if (Object.keys (query).length) {
+ url += '?' + signed;
+ }
+ } else if (method === 'POST') {
+ url += '?sign=' + signature + '&req_time=' + timestamp + '&accesskey=' + this.apiKey;
+ body = auth;
+ headers = {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ };
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (!response) {
+ return; // fallback to default error handler
+ }
+ //
+ // spot
+ //
+ // {"status":"fail","err_code":"01001","err_msg":"系统异常,请稍后重试"}
+ // {"status":"error","ts":1595594160149,"err_code":"invalid-parameter","err_msg":"invalid size, valid range: [1,2000]"}
+ // {"status":"error","ts":1595684716042,"err_code":"invalid-parameter","err_msg":"illegal sign invalid"}
+ // {"status":"error","ts":1595700216275,"err_code":"bad-request","err_msg":"your balance is low!"}
+ // {"status":"error","ts":1595700344504,"err_code":"invalid-parameter","err_msg":"invalid type"}
+ // {"status":"error","ts":1595703343035,"err_code":"bad-request","err_msg":"order cancel fail"}
+ // {"status":"error","ts":1595704360508,"err_code":"invalid-parameter","err_msg":"accesskey not null"}
+ // {"status":"error","ts":1595704490084,"err_code":"invalid-parameter","err_msg":"permissions not right"}
+ // {"status":"error","ts":1595711862763,"err_code":"system exception","err_msg":"system exception"}
+ // {"status":"error","ts":1595730308979,"err_code":"bad-request","err_msg":"20003"}
+ //
+ // swap
+ //
+ // {"code":"40015","msg":"","requestTime":1595698564931,"data":null}
+ // {"code":"40017","msg":"Order id must not be blank","requestTime":1595702477835,"data":null}
+ // {"code":"40017","msg":"Order Type must not be blank","requestTime":1595698516162,"data":null}
+ // {"code":"40301","msg":"","requestTime":1595667662503,"data":null}
+ // {"code":"40017","msg":"Contract code must not be blank","requestTime":1595703151651,"data":null}
+ // {"code":"40108","msg":"","requestTime":1595885064600,"data":null}
+ // {"order_id":"513468410013679613","client_oid":null,"symbol":"ethusd","result":false,"err_code":"order_no_exist_error","err_msg":"订单不存在!"}
+ //
+ const message = this.safeString (response, 'err_msg');
+ const errorCode = this.safeString2 (response, 'code', 'err_code');
+ const feedback = this.id + ' ' + body;
+ const nonEmptyMessage = ((message !== undefined) && (message !== ''));
+ if (nonEmptyMessage) {
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ }
+ const nonZeroErrorCode = (errorCode !== undefined) && (errorCode !== '00000');
+ if (nonZeroErrorCode) {
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ }
+ if (nonZeroErrorCode || nonEmptyMessage) {
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],34:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, ExchangeNotAvailable, AuthenticationError, BadRequest, PermissionDenied, InvalidAddress, ArgumentsRequired, InvalidOrder } = require ('./base/errors');
+const { DECIMAL_PLACES, SIGNIFICANT_DIGITS, TRUNCATE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -17085,13 +19697,18 @@ module.exports = class bithumb extends Exchange {
'countries': [ 'KR' ], // South Korea
'rateLimit': 500,
'has': {
- 'CORS': true,
- 'createOrder': true,
'cancelOrder': true,
+ 'CORS': true,
'createMarketOrder': true,
- 'fetchTickers': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'urls': {
@@ -17140,6 +19757,7 @@ module.exports = class bithumb extends Exchange {
'taker': 0.25 / 100,
},
},
+ 'precisionMode': SIGNIFICANT_DIGITS,
'exceptions': {
'Bad Request(SSL)': BadRequest,
'Bad Request(Bad Method)': BadRequest,
@@ -17158,19 +19776,23 @@ module.exports = class bithumb extends Exchange {
});
}
+ amountToPrecision (symbol, amount) {
+ return this.decimalToPrecision (amount, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES);
+ }
+
async fetchMarkets (params = {}) {
const response = await this.publicGetTickerAll (params);
const data = this.safeValue (response, 'data');
const currencyIds = Object.keys (data);
const result = [];
+ const quote = this.safeCurrencyCode ('KRW');
for (let i = 0; i < currencyIds.length; i++) {
const currencyId = currencyIds[i];
if (currencyId === 'date') {
continue;
}
const market = data[currencyId];
- const base = currencyId;
- const quote = 'KRW';
+ const base = this.safeCurrencyCode (currencyId);
const symbol = currencyId + '/' + quote;
let active = true;
if (Array.isArray (market)) {
@@ -17187,8 +19809,8 @@ module.exports = class bithumb extends Exchange {
'info': market,
'active': active,
'precision': {
- 'amount': undefined,
- 'price': undefined,
+ 'amount': 4,
+ 'price': 4,
},
'limits': {
'amount': {
@@ -17200,8 +19822,8 @@ module.exports = class bithumb extends Exchange {
'max': undefined,
},
'cost': {
- 'min': undefined,
- 'max': undefined,
+ 'min': 500,
+ 'max': 5000000000,
},
},
'baseId': undefined,
@@ -17306,10 +19928,7 @@ module.exports = class bithumb extends Exchange {
}
const baseVolume = this.safeFloat (ticker, 'units_traded_24H');
const quoteVolume = this.safeFloat (ticker, 'acc_trade_value_24H');
- let vwap = undefined;
- if (quoteVolume !== undefined && baseVolume !== undefined) {
- vwap = quoteVolume / baseVolume;
- }
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -17378,7 +19997,7 @@ module.exports = class bithumb extends Exchange {
result[symbol] = this.parseTicker (ticker, market);
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -17463,7 +20082,7 @@ module.exports = class bithumb extends Exchange {
symbol = market['symbol'];
}
const price = this.safeFloat (trade, 'price');
- const amount = this.safeFloat (trade, 'units_traded');
+ const amount = this.safeFloat2 (trade, 'units_traded', 'units');
let cost = this.safeFloat (trade, 'total');
if (cost === undefined) {
if (amount !== undefined) {
@@ -17573,25 +20192,26 @@ module.exports = class bithumb extends Exchange {
// {
// "status": "0000",
// "data": {
- // "transaction_date": "1572497603668315",
- // "type": "bid",
- // "order_status": "Completed",
- // "order_currency": "BTC",
- // "payment_currency": "KRW",
- // "order_price": "8601000",
- // "order_qty": "0.007",
- // "cancel_date": "",
- // "cancel_type": "",
- // "contract": [
+ // order_date: '1603161798539254',
+ // type: 'ask',
+ // order_status: 'Cancel',
+ // order_currency: 'BTC',
+ // payment_currency: 'KRW',
+ // watch_price: '0',
+ // order_price: '13344000',
+ // order_qty: '0.0125',
+ // cancel_date: '1603161803809993',
+ // cancel_type: '사용자취소',
+ // contract: [
// {
- // "transaction_date": "1572497603902030",
- // "price": "8601000",
- // "units": "0.005",
- // "fee_currency": "KRW",
- // "fee": "107.51",
- // "total": "43005"
- // },
- // ]
+ // transaction_date: '1603161799976383',
+ // price: '13344000',
+ // units: '0.0015',
+ // fee_currency: 'KRW',
+ // fee: '0',
+ // total: '20016'
+ // }
+ // ],
// }
// }
//
@@ -17609,6 +20229,7 @@ module.exports = class bithumb extends Exchange {
}
parseOrder (order, market = undefined) {
+ //
//
// fetchOrder
//
@@ -17634,6 +20255,29 @@ module.exports = class bithumb extends Exchange {
// ]
// }
//
+ // {
+ // order_date: '1603161798539254',
+ // type: 'ask',
+ // order_status: 'Cancel',
+ // order_currency: 'BTC',
+ // payment_currency: 'KRW',
+ // watch_price: '0',
+ // order_price: '13344000',
+ // order_qty: '0.0125',
+ // cancel_date: '1603161803809993',
+ // cancel_type: '사용자취소',
+ // contract: [
+ // {
+ // transaction_date: '1603161799976383',
+ // price: '13344000',
+ // units: '0.0015',
+ // fee_currency: 'KRW',
+ // fee: '0',
+ // total: '20016'
+ // }
+ // ],
+ // }
+ //
// fetchOpenOrders
//
// {
@@ -17662,14 +20306,10 @@ module.exports = class bithumb extends Exchange {
if (remaining === undefined) {
if (status === 'closed') {
remaining = 0;
- } else {
+ } else if (status !== 'canceled') {
remaining = amount;
}
}
- let filled = undefined;
- if ((amount !== undefined) && (remaining !== undefined)) {
- filled = amount - remaining;
- }
let symbol = undefined;
const baseId = this.safeString (order, 'order_currency');
const quoteId = this.safeString (order, 'payment_currency');
@@ -17681,35 +20321,92 @@ module.exports = class bithumb extends Exchange {
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
+ let filled = undefined;
+ let cost = undefined;
+ let average = undefined;
+ const id = this.safeString (order, 'order_id');
const rawTrades = this.safeValue (order, 'contract');
let trades = undefined;
- const id = this.safeString (order, 'order_id');
+ let fee = undefined;
+ let fees = undefined;
+ let feesByCurrency = undefined;
if (rawTrades !== undefined) {
trades = this.parseTrades (rawTrades, market, undefined, undefined, {
'side': side,
'symbol': symbol,
'order': id,
});
+ filled = 0;
+ feesByCurrency = {};
+ for (let i = 0; i < trades.length; i++) {
+ const trade = trades[i];
+ filled = this.sum (filled, trade['amount']);
+ cost = this.sum (cost, trade['cost']);
+ const tradeFee = trade['fee'];
+ const feeCurrency = tradeFee['currency'];
+ if (feeCurrency in feesByCurrency) {
+ feesByCurrency[feeCurrency] = {
+ 'currency': feeCurrency,
+ 'cost': this.sum (feesByCurrency[feeCurrency]['cost'], tradeFee['cost']),
+ };
+ } else {
+ feesByCurrency[feeCurrency] = {
+ 'currency': feeCurrency,
+ 'cost': tradeFee['cost'],
+ };
+ }
+ }
+ const feeCurrencies = Object.keys (feesByCurrency);
+ const feeCurrenciesLength = feeCurrencies.length;
+ if (feeCurrenciesLength > 1) {
+ fees = [];
+ for (let i = 0; i < feeCurrencies.length; i++) {
+ const feeCurrency = feeCurrencies[i];
+ fees.push (feesByCurrency[feeCurrency]);
+ }
+ } else {
+ fee = this.safeValue (feesByCurrency, feeCurrencies[0]);
+ }
+ if (filled !== 0) {
+ average = cost / filled;
+ }
}
- return {
+ if (amount !== undefined) {
+ if ((filled === undefined) && (remaining !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ if ((remaining === undefined) && (filled !== undefined)) {
+ remaining = Math.max (0, amount - filled);
+ }
+ }
+ const result = {
'info': order,
'id': id,
+ 'clientOrderId': undefined,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
- 'cost': undefined,
- 'average': undefined,
+ 'cost': cost,
+ 'average': average,
'filled': filled,
'remaining': remaining,
'status': status,
'fee': undefined,
'trades': trades,
};
+ if (fee !== undefined) {
+ result['fee'] = fee;
+ } else if (fees !== undefined) {
+ result['fees'] = fees;
+ }
+ return result;
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -17823,12 +20520,12 @@ module.exports = class bithumb extends Exchange {
const nonce = this.nonce ().toString ();
const auth = endpoint + "\0" + body + "\0" + nonce; // eslint-disable-line quotes
const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha512');
- const signature64 = this.decode (this.stringToBase64 (this.encode (signature)));
+ const signature64 = this.decode (this.stringToBase64 (signature));
headers = {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'Api-Key': this.apiKey,
- 'Api-Sign': signature64.toString (),
+ 'Api-Sign': signature64,
'Api-Nonce': nonce,
};
}
@@ -17869,7 +20566,7 @@ module.exports = class bithumb extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],36:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],35:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -17897,13 +20594,15 @@ module.exports = class bitkk extends zb {
}
};
-},{"./zb.js":172}],37:[function(require,module,exports){
+},{"./zb.js":179}],36:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { AuthenticationError, ArgumentsRequired, ExchangeError, InvalidOrder, BadRequest, OrderNotFound, DDoSProtection, BadSymbol } = require ('./base/errors');
+const { AuthenticationError, ExchangeNotAvailable, AccountSuspended, PermissionDenied, RateLimitExceeded, InvalidNonce, InvalidAddress, ArgumentsRequired, ExchangeError, InvalidOrder, InsufficientFunds, BadRequest, OrderNotFound, BadSymbol, NotSupported } = require ('./base/errors');
+const { ROUND, TICK_SIZE, TRUNCATE } = require ('./base/functions/number');
+
// ---------------------------------------------------------------------------
module.exports = class bitmart extends Exchange {
@@ -17913,33 +20612,38 @@ module.exports = class bitmart extends Exchange {
'name': 'BitMart',
'countries': [ 'US', 'CN', 'HK', 'KR' ],
'rateLimit': 1000,
- 'version': 'v2',
+ 'version': 'v1',
'has': {
- 'CORS': true,
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'cancelOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchCanceledOrders': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchOrderTrades': true,
'fetchTicker': true,
'fetchTickers': true,
'fetchTime': true,
- 'fetchCurrencies': true,
- 'fetchOrderBook': true,
+ 'fetchStatus': true,
'fetchTrades': true,
- 'fetchMyTrades': true,
- 'fetchOHLCV': true,
- 'fetchBalance': true,
- 'createOrder': true,
- 'cancelOrder': true,
- 'cancelAllOrders': true,
- 'fetchOrders': false,
- 'fetchOrderTrades': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'fetchCanceledOrders': true,
- 'fetchOrder': true,
- 'signIn': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
+ 'hostname': 'bitmart.com', // bitmart.info for Hong Kong users
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/61835713-a2662f80-ae85-11e9-9d00-6442919701fd.jpg',
- 'api': 'https://openapi.bitmart.com',
+ 'api': 'https://api-cloud.{hostname}', // bitmart.info for Hong Kong users
'www': 'https://www.bitmart.com/',
'doc': 'https://github.com/bitmartexchange/bitmart-official-api-docs',
'referral': 'http://www.bitmart.com/?r=rQCFLh',
@@ -17951,39 +20655,88 @@ module.exports = class bitmart extends Exchange {
'uid': true,
},
'api': {
- 'token': {
- 'post': [
- 'authentication',
- ],
- },
'public': {
- 'get': [
- 'currencies',
- 'ping',
- 'steps',
- 'symbols',
- 'symbols_details',
- 'symbols/{symbol}/kline',
- 'symbols/{symbol}/orders',
- 'symbols/{symbol}/trades',
- 'ticker',
- 'time',
- ],
+ 'system': {
+ 'get': [
+ 'time', // https://api-cloud.bitmart.com/system/time
+ 'service', // https://api-cloud.bitmart.com/system/service
+ ],
+ },
+ 'account': {
+ 'get': [
+ 'currencies', // https://api-cloud.bitmart.com/account/v1/currencies
+ ],
+ },
+ 'spot': {
+ 'get': [
+ 'currencies',
+ 'symbols',
+ 'symbols/details',
+ 'ticker', // ?symbol=BTC_USDT
+ 'steps', // ?symbol=BMX_ETH
+ 'symbols/kline', // ?symbol=BMX_ETH&step=15&from=1525760116&to=1525769116
+ 'symbols/book', // ?symbol=BMX_ETH&precision=6
+ 'symbols/trades', // ?symbol=BMX_ETH
+ ],
+ },
+ 'contract': {
+ 'get': [
+ 'contracts', // https://api-cloud.bitmart.com/contract/v1/ifcontract/contracts
+ 'pnls',
+ 'indexes',
+ 'tickers',
+ 'quote',
+ 'indexquote',
+ 'trades',
+ 'depth',
+ 'fundingrate',
+ ],
+ },
},
'private': {
- 'get': [
- 'orders',
- 'orders/{id}',
- 'trades',
- 'wallet',
- ],
- 'post': [
- 'orders',
- ],
- 'delete': [
- 'orders',
- 'orders/{id}',
- ],
+ 'account': {
+ 'get': [
+ 'wallet', // ?account_type=1
+ 'deposit/address', // ?currency=USDT-TRC20
+ 'withdraw/charge', // ?currency=BTC
+ 'deposit-withdraw/history', // ?limit=10&offset=1&operationType=withdraw
+ 'deposit-withdraw/detail', // ?id=1679952
+ ],
+ 'post': [
+ 'withdraw/apply',
+ ],
+ },
+ 'spot': {
+ 'get': [
+ 'wallet',
+ 'order_detail',
+ 'orders',
+ 'trades',
+ ],
+ 'post': [
+ 'submit_order', // https://api-cloud.bitmart.com/spot/v1/submit_order
+ 'cancel_order', // https://api-cloud.bitmart.com/spot/v2/cancel_order
+ 'cancel_orders',
+ ],
+ },
+ 'contract': {
+ 'get': [
+ 'userOrders',
+ 'userOrderInfo',
+ 'userTrades',
+ 'orderTrades',
+ 'accounts',
+ 'userPositions',
+ 'userLiqRecords',
+ 'positionFee',
+ ],
+ 'post': [
+ 'batchOrders',
+ 'submitOrder',
+ 'cancelOrders',
+ 'marginOper',
+ ],
+ },
},
},
'timeframes': {
@@ -18031,81 +20784,236 @@ module.exports = class bitmart extends Exchange {
},
},
},
+ 'precisionMode': TICK_SIZE,
'exceptions': {
'exact': {
- 'Place order error': InvalidOrder, // {"message":"Place order error"}
- 'Not found': OrderNotFound, // {"message":"Not found"}
- 'Visit too often, please try again later': DDoSProtection, // {"code":-30,"msg":"Visit too often, please try again later","subMsg":"","data":{}}
- 'Unknown symbol': BadSymbol, // {"message":"Unknown symbol"}
- },
- 'broad': {
- 'Invalid limit. limit must be in the range': InvalidOrder,
- 'Maximum price is': InvalidOrder, // {"message":"Maximum price is 0.112695"}
- // {"message":"Required Integer parameter 'status' is not present"}
- // {"message":"Required String parameter 'symbol' is not present"}
- // {"message":"Required Integer parameter 'offset' is not present"}
- // {"message":"Required Integer parameter 'limit' is not present"}
- // {"message":"Required Long parameter 'from' is not present"}
- // {"message":"Required Long parameter 'to' is not present"}
- 'is not present': BadRequest,
+ // general errors
+ '30000': ExchangeError, // 404, Not found
+ '30001': AuthenticationError, // 401, Header X-BM-KEY is empty
+ '30002': AuthenticationError, // 401, Header X-BM-KEY not found
+ '30003': AccountSuspended, // 401, Header X-BM-KEY has frozen
+ '30004': AuthenticationError, // 401, Header X-BM-SIGN is empty
+ '30005': AuthenticationError, // 401, Header X-BM-SIGN is wrong
+ '30006': AuthenticationError, // 401, Header X-BM-TIMESTAMP is empty
+ '30007': AuthenticationError, // 401, Header X-BM-TIMESTAMP range. Within a minute
+ '30008': AuthenticationError, // 401, Header X-BM-TIMESTAMP invalid format
+ '30010': PermissionDenied, // 403, IP is forbidden. We recommend enabling IP whitelist for API trading. After that reauth your account
+ '30011': AuthenticationError, // 403, Header X-BM-KEY over expire time
+ '30012': AuthenticationError, // 403, Header X-BM-KEY is forbidden to request it
+ '30013': RateLimitExceeded, // 429, Request too many requests
+ '30014': ExchangeNotAvailable, // 503, Service unavailable
+ // funding account errors
+ '60000': BadRequest, // 400, Invalid request (maybe the body is empty, or the int parameter passes string data)
+ '60001': BadRequest, // 400, Asset account type does not exist
+ '60002': BadRequest, // 400, currency does not exist
+ '60003': ExchangeError, // 400, Currency has been closed recharge channel, if there is any problem, please consult customer service
+ '60004': ExchangeError, // 400, Currency has been closed withdraw channel, if there is any problem, please consult customer service
+ '60005': ExchangeError, // 400, Minimum amount is %s
+ '60006': ExchangeError, // 400, Maximum withdraw precision is %d
+ '60007': InvalidAddress, // 400, Only withdrawals from added addresses are allowed
+ '60008': InsufficientFunds, // 400, Balance not enough
+ '60009': ExchangeError, // 400, Beyond the limit
+ '60010': ExchangeError, // 400, Withdraw id or deposit id not found
+ '60011': InvalidAddress, // 400, Address is not valid
+ '60012': ExchangeError, // 400, This action is not supported in this currency(If IOTA, HLX recharge and withdraw calls are prohibited)
+ '60020': PermissionDenied, // 403, Your account is not allowed to recharge
+ '60021': PermissionDenied, // 403, Your account is not allowed to withdraw
+ '60022': PermissionDenied, // 403, No withdrawals for 24 hours
+ '60030': BadRequest, // 405, Method Not Allowed
+ '60031': BadRequest, // 415, Unsupported Media Type
+ '60050': ExchangeError, // 500, User account not found
+ '60051': ExchangeError, // 500, Internal Server Error
+ // spot errors
+ '50000': BadRequest, // 400, Bad Request
+ '50001': BadSymbol, // 400, Symbol not found
+ '50002': BadRequest, // 400, From Or To format error
+ '50003': BadRequest, // 400, Step format error
+ '50004': BadRequest, // 400, Kline size over 500
+ '50005': OrderNotFound, // 400, Order Id not found
+ '50006': InvalidOrder, // 400, Minimum size is %s
+ '50007': InvalidOrder, // 400, Maximum size is %s
+ '50008': InvalidOrder, // 400, Minimum price is %s
+ '50009': InvalidOrder, // 400, Minimum count*price is %s
+ '50010': InvalidOrder, // 400, RequestParam size is required
+ '50011': InvalidOrder, // 400, RequestParam price is required
+ '50012': InvalidOrder, // 400, RequestParam notional is required
+ '50013': InvalidOrder, // 400, Maximum limit*offset is %d
+ '50014': BadRequest, // 400, RequestParam limit is required
+ '50015': BadRequest, // 400, Minimum limit is 1
+ '50016': BadRequest, // 400, Maximum limit is %d
+ '50017': BadRequest, // 400, RequestParam offset is required
+ '50018': BadRequest, // 400, Minimum offset is 1
+ '50019': BadRequest, // 400, Maximum price is %s
+ // '50019': ExchangeError, // 400, Invalid status. validate status is [1=Failed, 2=Success, 3=Frozen Failed, 4=Frozen Success, 5=Partially Filled, 6=Fully Fulled, 7=Canceling, 8=Canceled
+ '50020': InsufficientFunds, // 400, Balance not enough
+ '50021': BadRequest, // 400, Invalid %s
+ '50022': ExchangeNotAvailable, // 400, Service unavailable
+ '50023': BadSymbol, // 400, This Symbol can't place order by api
+ '53000': AccountSuspended, // 403, Your account is frozen due to security policies. Please contact customer service
+ '57001': BadRequest, // 405, Method Not Allowed
+ '58001': BadRequest, // 415, Unsupported Media Type
+ '59001': ExchangeError, // 500, User account not found
+ '59002': ExchangeError, // 500, Internal Server Error
+ // contract errors
+ '40001': ExchangeError, // 400, Cloud account not found
+ '40002': ExchangeError, // 400, out_trade_no not found
+ '40003': ExchangeError, // 400, out_trade_no already existed
+ '40004': ExchangeError, // 400, Cloud account count limit
+ '40005': ExchangeError, // 400, Transfer vol precision error
+ '40006': PermissionDenied, // 400, Invalid ip error
+ '40007': BadRequest, // 400, Parse parameter error
+ '40008': InvalidNonce, // 400, Check nonce error
+ '40009': BadRequest, // 400, Check ver error
+ '40010': BadRequest, // 400, Not found func error
+ '40011': BadRequest, // 400, Invalid request
+ '40012': ExchangeError, // 500, System error
+ '40013': ExchangeError, // 400, Access too often" CLIENT_TIME_INVALID, "Please check your system time.
+ '40014': BadSymbol, // 400, This contract is offline
+ '40015': BadSymbol, // 400, This contract's exchange has been paused
+ '40016': InvalidOrder, // 400, This order would trigger user position liquidate
+ '40017': InvalidOrder, // 400, It is not possible to open and close simultaneously in the same position
+ '40018': InvalidOrder, // 400, Your position is closed
+ '40019': ExchangeError, // 400, Your position is in liquidation delegating
+ '40020': InvalidOrder, // 400, Your position volume is not enough
+ '40021': ExchangeError, // 400, The position is not exsit
+ '40022': ExchangeError, // 400, The position is not isolated
+ '40023': ExchangeError, // 400, The position would liquidate when sub margin
+ '40024': ExchangeError, // 400, The position would be warnning of liquidation when sub margin
+ '40025': ExchangeError, // 400, The position’s margin shouldn’t be lower than the base limit
+ '40026': ExchangeError, // 400, You cross margin position is in liquidation delegating
+ '40027': InsufficientFunds, // 400, You contract account available balance not enough
+ '40028': PermissionDenied, // 400, Your plan order's count is more than system maximum limit.
+ '40029': InvalidOrder, // 400, The order's leverage is too large.
+ '40030': InvalidOrder, // 400, The order's leverage is too small.
+ '40031': InvalidOrder, // 400, The deviation between current price and trigger price is too large.
+ '40032': InvalidOrder, // 400, The plan order's life cycle is too long.
+ '40033': InvalidOrder, // 400, The plan order's life cycle is too short.
+ '40034': BadSymbol, // 400, This contract is not found
},
+ 'broad': {},
},
'commonCurrencies': {
'ONE': 'Menlo One',
'PLA': 'Plair',
},
+ 'options': {
+ 'defaultType': 'spot', // 'spot', 'swap'
+ 'fetchBalance': {
+ 'type': 'spot', // 'spot', 'swap', 'contract', 'account'
+ },
+ 'createMarketBuyOrderRequiresPrice': true,
+ },
});
}
async fetchTime (params = {}) {
- const response = await this.publicGetTime (params);
+ const response = await this.publicSystemGetTime (params);
//
// {
- // "server_time": 1527777538000
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"c4e5e5b7-fe9f-4191-89f7-53f6c5bf9030",
+ // "data":{
+ // "server_time":1599843709578
+ // }
// }
//
- return this.safeInteger (response, 'server_time');
+ const data = this.safeValue (response, 'data', {});
+ return this.safeInteger (data, 'server_time');
}
- async signIn (params = {}) {
- const message = this.apiKey + ':' + this.secret + ':' + this.uid;
- const data = {
- 'grant_type': 'client_credentials',
- 'client_id': this.apiKey,
- 'client_secret': this.hmac (this.encode (message), this.encode (this.secret), 'sha256'),
- };
- const response = await this.tokenPostAuthentication (this.extend (data, params));
- const accessToken = this.safeString (response, 'access_token');
- if (!accessToken) {
- throw new AuthenticationError (this.id + ' signIn() failed to authenticate. Access token missing from response.');
- }
- const expiresIn = this.safeInteger (response, 'expires_in');
- this.options['expires'] = this.sum (this.nonce (), expiresIn * 1000);
- this.options['accessToken'] = accessToken;
- return response;
- }
-
- async fetchMarkets (params = {}) {
- const markets = await this.publicGetSymbolsDetails (params);
+ async fetchStatus (params = {}) {
+ const options = this.safeValue (this.options, 'fetchBalance', {});
+ const defaultType = this.safeString (this.options, 'defaultType');
+ let type = this.safeString (options, 'type', defaultType);
+ type = this.safeString (params, 'type', type);
+ params = this.omit (params, 'type');
+ const response = await this.publicSystemGetService (params);
//
- // [
- // {
- // "id":"1SG_BTC",
- // "base_currency":"1SG",
- // "quote_currency":"BTC",
- // "quote_increment":"0.1",
- // "base_min_size":"0.1000000000",
- // "base_max_size":"10000000.0000000000",
- // "price_min_precision":4,
- // "price_max_precision":6,
- // "expiration":"NA"
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "serivce":[
+ // {
+ // "title": "Spot API Stop",
+ // "service_type": "spot",
+ // "status": "2",
+ // "start_time": 1527777538000,
+ // "end_time": 1527777538000
+ // },
+ // {
+ // "title": "Contract API Stop",
+ // "service_type": "contract",
+ // "status": "2",
+ // "start_time": 1527777538000,
+ // "end_time": 1527777538000
+ // }
+ // ]
// }
- // ]
+ // }
//
+ const data = this.safeValue (response, 'data', {});
+ const services = this.safeValue (data, 'service', []);
+ const servicesByType = this.indexBy (services, 'service_type');
+ if ((type === 'swap') || (type === 'future')) {
+ type = 'contract';
+ }
+ const service = this.safeValue (servicesByType, type);
+ let status = undefined;
+ let eta = undefined;
+ if (service !== undefined) {
+ const statusCode = this.safeInteger (service, 'status');
+ if (statusCode === 2) {
+ status = 'ok';
+ } else {
+ status = 'maintenance';
+ eta = this.safeInteger (service, 'end_time');
+ }
+ }
+ this.status = this.extend (this.status, {
+ 'status': status,
+ 'updated': this.milliseconds (),
+ 'eta': eta,
+ });
+ return this.status;
+ }
+
+ async fetchSpotMarkets (params = {}) {
+ const response = await this.publicSpotGetSymbolsDetails (params);
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"a67c9146-086d-4d3f-9897-5636a9bb26e1",
+ // "data":{
+ // "symbols":[
+ // {
+ // "symbol":"PRQ_BTC",
+ // "symbol_id":1232,
+ // "base_currency":"PRQ",
+ // "quote_currency":"BTC",
+ // "quote_increment":"1.0000000000",
+ // "base_min_size":"1.0000000000",
+ // "base_max_size":"10000000.0000000000",
+ // "price_min_precision":8,
+ // "price_max_precision":10,
+ // "expiration":"NA",
+ // "min_buy_amount":"0.0001000000",
+ // "min_sell_amount":"0.0001000000"
+ // },
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const symbols = this.safeValue (data, 'symbols', []);
const result = [];
- for (let i = 0; i < markets.length; i++) {
- const market = markets[i];
- const id = this.safeString (market, 'id');
+ for (let i = 0; i < symbols.length; i++) {
+ const market = symbols[i];
+ const id = this.safeString (market, 'symbol');
+ const numericId = this.safeInteger (market, 'symbol_id');
const baseId = this.safeString (market, 'base_currency');
const quoteId = this.safeString (market, 'quote_currency');
const base = this.safeCurrencyCode (baseId);
@@ -18120,13 +21028,14 @@ module.exports = class bitmart extends Exchange {
//
// the docs are wrong: https://github.com/ccxt/ccxt/issues/5612
//
- const quoteIncrement = this.safeString (market, 'quote_increment');
- const amountPrecision = this.precisionFromString (quoteIncrement);
const pricePrecision = this.safeInteger (market, 'price_max_precision');
const precision = {
- 'amount': amountPrecision,
- 'price': pricePrecision,
+ 'amount': this.safeFloat (market, 'base_min_size'),
+ 'price': parseFloat (this.decimalToPrecision (Math.pow (10, -pricePrecision), ROUND, 10)),
};
+ const minBuyCost = this.safeFloat (market, 'min_buy_amount');
+ const minSellCost = this.safeFloat (market, 'min_sell_amount');
+ const minCost = Math.max (minBuyCost, minSellCost);
const limits = {
'amount': {
'min': this.safeFloat (market, 'base_min_size'),
@@ -18137,17 +21046,22 @@ module.exports = class bitmart extends Exchange {
'max': undefined,
},
'cost': {
- 'min': undefined,
+ 'min': minCost,
'max': undefined,
},
};
result.push ({
'id': id,
+ 'numericId': numericId,
'symbol': symbol,
'base': base,
'quote': quote,
'baseId': baseId,
'quoteId': quoteId,
+ 'type': 'spot',
+ 'spot': true,
+ 'future': false,
+ 'swap': false,
'precision': precision,
'limits': limits,
'info': market,
@@ -18157,107 +21071,388 @@ module.exports = class bitmart extends Exchange {
return result;
}
- parseTicker (ticker, market = undefined) {
- const timestamp = this.milliseconds ();
- const marketId = this.safeString (ticker, 'symbol_id');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else if (marketId !== undefined) {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
+ async fetchContractMarkets (params = {}) {
+ const response = await this.publicContractGetContracts (params);
+ //
+ // {
+ // "errno":"OK",
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"7fcedfb5-a660-4780-8a7a-b36a9e2159f7",
+ // "data":{
+ // "contracts":[
+ // {
+ // "contract":{
+ // "contract_id":1,
+ // "index_id":1,
+ // "name":"BTCUSDT",
+ // "display_name":"BTCUSDT永续合约",
+ // "display_name_en":"BTCUSDT_SWAP",
+ // "contract_type":1,
+ // "base_coin":"BTC",
+ // "quote_coin":"USDT",
+ // "price_coin":"BTC",
+ // "exchange":"*",
+ // "contract_size":"0.0001",
+ // "begin_at":"2018-08-17T04:00:00Z",
+ // "delive_at":"2020-08-15T12:00:00Z",
+ // "delivery_cycle":28800,
+ // "min_leverage":"1",
+ // "max_leverage":"100",
+ // "price_unit":"0.1",
+ // "vol_unit":"1",
+ // "value_unit":"0.0001",
+ // "min_vol":"1",
+ // "max_vol":"300000",
+ // "liquidation_warn_ratio":"0.85",
+ // "fast_liquidation_ratio":"0.8",
+ // "settgle_type":1,
+ // "open_type":3,
+ // "compensate_type":1,
+ // "status":3,
+ // "block":1,
+ // "rank":1,
+ // "created_at":"2018-07-12T19:16:57Z",
+ // "depth_bord":"1.001",
+ // "base_coin_zh":"比特币",
+ // "base_coin_en":"Bitcoin",
+ // "max_rate":"0.00375",
+ // "min_rate":"-0.00375"
+ // },
+ // "risk_limit":{"contract_id":1,"base_limit":"1000000","step":"500000","maintenance_margin":"0.005","initial_margin":"0.01"},
+ // "fee_config":{"contract_id":1,"maker_fee":"-0.0003","taker_fee":"0.001","settlement_fee":"0","created_at":"2018-07-12T20:47:22Z"},
+ // "plan_order_config":{"contract_id":0,"min_scope":"0.001","max_scope":"2","max_count":10,"min_life_cycle":24,"max_life_cycle":168}
+ // },
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const contracts = this.safeValue (data, 'contracts', []);
+ const result = [];
+ for (let i = 0; i < contracts.length; i++) {
+ const market = contracts[i];
+ const contract = this.safeValue (market, 'contract', {});
+ const id = this.safeString (contract, 'contract_id');
+ const numericId = this.safeInteger (contract, 'contract_id');
+ const baseId = this.safeString (contract, 'base_coin');
+ const quoteId = this.safeString (contract, 'quote_coin');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = this.safeString (contract, 'name');
+ //
+ // https://github.com/bitmartexchange/bitmart-official-api-docs/blob/master/rest/public/symbols_details.md#response-details
+ // from the above API doc:
+ // quote_increment Minimum order price as well as the price increment
+ // price_min_precision Minimum price precision (digit) used to query price and kline
+ // price_max_precision Maximum price precision (digit) used to query price and kline
+ //
+ // the docs are wrong: https://github.com/ccxt/ccxt/issues/5612
+ //
+ const amountPrecision = this.safeFloat (contract, 'vol_unit');
+ const pricePrecision = this.safeFloat (contract, 'price_unit');
+ const precision = {
+ 'amount': amountPrecision,
+ 'price': pricePrecision,
+ };
+ const limits = {
+ 'amount': {
+ 'min': this.safeFloat (contract, 'min_vol'),
+ 'max': this.safeFloat (contract, 'max_vol'),
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ };
+ const contractType = this.safeValue (contract, 'contract_type');
+ let future = false;
+ let swap = false;
+ let type = 'contract';
+ if (contractType === 1) {
+ type = 'swap';
+ swap = true;
+ } else if (contractType === 2) {
+ type = 'future';
+ future = true;
}
+ const feeConfig = this.safeValue (market, 'fee_config', {});
+ const maker = this.safeFloat (feeConfig, 'maker_fee');
+ const taker = this.safeFloat (feeConfig, 'taker_fee');
+ result.push ({
+ 'id': id,
+ 'numericId': numericId,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'maker': maker,
+ 'taker': taker,
+ 'type': type,
+ 'spot': false,
+ 'future': future,
+ 'swap': swap,
+ 'precision': precision,
+ 'limits': limits,
+ 'info': market,
+ 'active': undefined,
+ });
}
- const last = this.safeFloat (ticker, 'current_price');
- const percentage = this.safeFloat (ticker, 'fluctuation');
+ return result;
+ }
+
+ async fetchMarkets (params = {}) {
+ const spotMarkets = await this.fetchSpotMarkets ();
+ const contractMarkets = await this.fetchContractMarkets ();
+ const allMarkets = this.arrayConcat (spotMarkets, contractMarkets);
+ return allMarkets;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // spot
+ //
+ // {
+ // "symbol":"ETH_BTC",
+ // "last_price":"0.036037",
+ // "quote_volume_24h":"4380.6660000000",
+ // "base_volume_24h":"159.3582006712",
+ // "high_24h":"0.036972",
+ // "low_24h":"0.035524",
+ // "open_24h":"0.036561",
+ // "close_24h":"0.036037",
+ // "best_ask":"0.036077",
+ // "best_ask_size":"9.9500",
+ // "best_bid":"0.035983",
+ // "best_bid_size":"4.2792",
+ // "fluctuation":"-0.0143",
+ // "url":"https://www.bitmart.com/trade?symbol=ETH_BTC"
+ // }
+ //
+ // contract
+ //
+ // {
+ // "last_price":"422.2",
+ // "open":"430.5",
+ // "close":"422.2",
+ // "low":"421.9",
+ // "high":"436.9",
+ // "avg_price":"430.8569900089815372072",
+ // "volume":"2720",
+ // "total_volume":"18912248",
+ // "timestamp":1597631495,
+ // "rise_fall_rate":"-0.0192799070847851336",
+ // "rise_fall_value":"-8.3",
+ // "contract_id":2,
+ // "position_size":"3067404",
+ // "volume_day":"9557384",
+ // "amount24":"80995537.0919999999999974153",
+ // "base_coin_volume":"189122.48",
+ // "quote_coin_volume":"81484742.475833810590837937856",
+ // "pps":"1274350547",
+ // "index_price":"422.135",
+ // "fair_price":"422.147253318507",
+ // "depth_price":{"bid_price":"421.9","ask_price":"422","mid_price":"421.95"},
+ // "fair_basis":"0.000029027013",
+ // "fair_value":"0.012253318507",
+ // "rate":{"quote_rate":"0.0006","base_rate":"0.0003","interest_rate":"0.000099999999"},
+ // "premium_index":"0.000045851604",
+ // "funding_rate":"0.000158",
+ // "next_funding_rate":"0.000099999999",
+ // "next_funding_at":"2020-08-17T04:00:00Z"
+ // }
+ //
+ const timestamp = this.safeTimestamp (ticker, 'timestamp', this.milliseconds ());
+ const marketId = this.safeString2 (ticker, 'symbol', 'contract_id');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const last = this.safeFloat2 (ticker, 'close_24h', 'last_price');
+ let percentage = this.safeFloat (ticker, 'fluctuation', 'rise_fall_rate');
+ if (percentage !== undefined) {
+ percentage *= 100;
+ }
+ const baseVolume = this.safeFloat2 (ticker, 'base_volume_24h', 'base_coin_volume');
+ const quoteVolume = this.safeFloat2 (ticker, 'quote_volume_24h', 'quote_coin_volume');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ const open = this.safeFloat2 (ticker, 'open_24h', 'open');
+ let average = undefined;
+ if ((last !== undefined) && (open !== undefined)) {
+ average = this.sum (last, open) / 2;
+ }
+ average = this.safeFloat (ticker, 'avg_price', average);
+ const price = this.safeValue (ticker, 'depth_price', ticker);
return {
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'high': this.safeFloat (ticker, 'highest_price'),
- 'low': this.safeFloat (ticker, 'lowest_price'),
- 'bid': this.safeFloat (ticker, 'bid_1'),
- 'bidVolume': this.safeFloat (ticker, 'bid_1_amount'),
- 'ask': this.safeFloat (ticker, 'ask_1'),
- 'askVolume': this.safeFloat (ticker, 'ask_1_amount'),
- 'vwap': undefined,
- 'open': undefined,
+ 'high': this.safeFloat2 (ticker, 'high', 'high_24h'),
+ 'low': this.safeFloat2 (ticker, 'low', 'low_24h'),
+ 'bid': this.safeFloat (price, 'best_bid', 'bid_price'),
+ 'bidVolume': this.safeFloat (ticker, 'best_bid_size'),
+ 'ask': this.safeFloat (price, 'best_ask', 'ask_price'),
+ 'askVolume': this.safeFloat (ticker, 'best_ask_size'),
+ 'vwap': vwap,
+ 'open': this.safeFloat (ticker, 'open_24h'),
'close': last,
'last': last,
'previousClose': undefined,
'change': undefined,
- 'percentage': percentage * 100,
- 'average': undefined,
- 'baseVolume': this.safeFloat (ticker, 'volume'),
- 'quoteVolume': this.safeFloat (ticker, 'base_volume'),
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
'info': ticker,
};
}
async fetchTicker (symbol, params = {}) {
await this.loadMarkets ();
- const request = {
- 'symbol': this.marketId (symbol),
- };
- const response = await this.publicGetTicker (this.extend (request, params));
+ const market = this.market (symbol);
+ const request = {};
+ let method = undefined;
+ if (market['swap'] || market['future']) {
+ method = 'publicContractGetTickers';
+ request['contractID'] = market['id'];
+ } else if (market['spot']) {
+ method = 'publicSpotGetTicker';
+ request['symbol'] = market['id'];
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
//
// {
- // "volume":"97487.38",
- // "ask_1":"0.00148668",
- // "base_volume":"144.59",
- // "lowest_price":"0.00144362",
- // "bid_1":"0.00148017",
- // "highest_price":"0.00151000",
- // "ask_1_amount":"92.03",
- // "current_price":"0.00148230",
- // "fluctuation":"+0.0227",
- // "symbol_id":"XRP_ETH",
- // "url":"https://www.bitmart.com/trade?symbol=XRP_ETH",
- // "bid_1_amount":"134.78"
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"6aa5b923-2f57-46e3-876d-feca190e0b82",
+ // "data":{
+ // "tickers":[
+ // {
+ // "symbol":"ETH_BTC",
+ // "last_price":"0.036037",
+ // "quote_volume_24h":"4380.6660000000",
+ // "base_volume_24h":"159.3582006712",
+ // "high_24h":"0.036972",
+ // "low_24h":"0.035524",
+ // "open_24h":"0.036561",
+ // "close_24h":"0.036037",
+ // "best_ask":"0.036077",
+ // "best_ask_size":"9.9500",
+ // "best_bid":"0.035983",
+ // "best_bid_size":"4.2792",
+ // "fluctuation":"-0.0143",
+ // "url":"https://www.bitmart.com/trade?symbol=ETH_BTC"
+ // }
+ // ]
+ // }
// }
//
- return this.parseTicker (response);
+ // contract
+ //
+ // {
+ // "errno":"OK",
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"d09b57c4-d99b-4a13-91a8-2df98f889909",
+ // "data":{
+ // "tickers":[
+ // {
+ // "last_price":"422.2",
+ // "open":"430.5",
+ // "close":"422.2",
+ // "low":"421.9",
+ // "high":"436.9",
+ // "avg_price":"430.8569900089815372072",
+ // "volume":"2720",
+ // "total_volume":"18912248",
+ // "timestamp":1597631495,
+ // "rise_fall_rate":"-0.0192799070847851336",
+ // "rise_fall_value":"-8.3",
+ // "contract_id":2,
+ // "position_size":"3067404",
+ // "volume_day":"9557384",
+ // "amount24":"80995537.0919999999999974153",
+ // "base_coin_volume":"189122.48",
+ // "quote_coin_volume":"81484742.475833810590837937856",
+ // "pps":"1274350547",
+ // "index_price":"422.135",
+ // "fair_price":"422.147253318507",
+ // "depth_price":{"bid_price":"421.9","ask_price":"422","mid_price":"421.95"},
+ // "fair_basis":"0.000029027013",
+ // "fair_value":"0.012253318507",
+ // "rate":{"quote_rate":"0.0006","base_rate":"0.0003","interest_rate":"0.000099999999"},
+ // "premium_index":"0.000045851604",
+ // "funding_rate":"0.000158",
+ // "next_funding_rate":"0.000099999999",
+ // "next_funding_at":"2020-08-17T04:00:00Z"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const tickers = this.safeValue (data, 'tickers', []);
+ const tickersById = this.indexBy (tickers, 'symbol');
+ const ticker = this.safeValue (tickersById, market['id']);
+ return this.parseTicker (ticker, market);
}
async fetchTickers (symbols = undefined, params = {}) {
await this.loadMarkets ();
- const tickers = await this.publicGetTicker (params);
+ const defaultType = this.safeString (this.options, 'defaultType', 'spot');
+ const type = this.safeString (params, 'type', defaultType);
+ params = this.omit (params, 'type');
+ let method = undefined;
+ if ((type === 'swap') || (type === 'future')) {
+ method = 'publicContractGetTickers';
+ } else if (type === 'spot') {
+ method = 'publicSpotGetTicker';
+ }
+ const response = await this[method] (params);
+ const data = this.safeValue (response, 'data', {});
+ const tickers = this.safeValue (data, 'tickers', []);
const result = {};
for (let i = 0; i < tickers.length; i++) {
const ticker = this.parseTicker (tickers[i]);
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchCurrencies (params = {}) {
- const currencies = await this.publicGetCurrencies (params);
+ const response = await this.publicAccountGetCurrencies (params);
//
- // [
- // {
- // "name":"CNY1",
- // "withdraw_enabled":false,
- // "id":"CNY1",
- // "deposit_enabled":false
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"8c768b3c-025f-413f-bec5-6d6411d46883",
+ // "data":{
+ // "currencies":[
+ // {"currency":"MATIC","name":"Matic Network","withdraw_enabled":true,"deposit_enabled":true},
+ // {"currency":"KTN","name":"Kasoutuuka News","withdraw_enabled":true,"deposit_enabled":false},
+ // {"currency":"BRT","name":"Berith","withdraw_enabled":true,"deposit_enabled":true},
+ // ]
// }
- // ]
+ // }
//
+ const data = this.safeValue (response, 'data', {});
+ const currencies = this.safeValue (data, 'currencies', []);
const result = {};
for (let i = 0; i < currencies.length; i++) {
const currency = currencies[i];
- const currencyId = this.safeString (currency, 'id');
- const code = this.safeCurrencyCode (currencyId);
+ const id = this.safeString (currency, 'currency');
+ const code = this.safeCurrencyCode (id);
const name = this.safeString (currency, 'name');
const withdrawEnabled = this.safeValue (currency, 'withdraw_enabled');
const depositEnabled = this.safeValue (currency, 'deposit_enabled');
const active = withdrawEnabled && depositEnabled;
result[code] = {
- 'id': currencyId,
+ 'id': id,
'code': code,
'name': name,
'info': currency, // the original payload
@@ -18277,79 +21472,151 @@ module.exports = class bitmart extends Exchange {
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
- const request = {
- 'symbol': this.marketId (symbol),
- // 'precision': 4, // optional price precision / depth level whose range is defined in symbol details
- };
- const response = await this.publicGetSymbolsSymbolOrders (this.extend (request, params));
- return this.parseOrderBook (response, undefined, 'buys', 'sells', 'price', 'amount');
+ const market = this.market (symbol);
+ const request = {};
+ let method = undefined;
+ if (market['spot']) {
+ method = 'publicSpotGetSymbolsBook';
+ request['symbol'] = market['id'];
+ // request['precision'] = 4; // optional price precision / depth level whose range is defined in symbol details
+ } else if (market['swap'] || market['future']) {
+ method = 'publicContractGetDepth';
+ request['contractID'] = market['id'];
+ if (limit !== undefined) {
+ request['count'] = limit; // returns all records if size is omitted
+ }
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"8254f8fc-431d-404f-ad9a-e716339f66c7",
+ // "data":{
+ // "buys":[
+ // {"amount":"4.7091","total":"4.71","price":"0.034047","count":"1"},
+ // {"amount":"5.7439","total":"10.45","price":"0.034039","count":"1"},
+ // {"amount":"2.5249","total":"12.98","price":"0.032937","count":"1"},
+ // ],
+ // "sells":[
+ // {"amount":"41.4365","total":"41.44","price":"0.034174","count":"1"},
+ // {"amount":"4.2317","total":"45.67","price":"0.034183","count":"1"},
+ // {"amount":"0.3000","total":"45.97","price":"0.034240","count":"1"},
+ // ]
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "errno":"OK",
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"c330dfca-ca5b-4f15-b350-9fef3f049b4f",
+ // "data":{
+ // "sells":[
+ // {"price":"347.6","vol":"6678"},
+ // {"price":"347.7","vol":"3452"},
+ // {"price":"347.8","vol":"6331"},
+ // ],
+ // "buys":[
+ // {"price":"347.5","vol":"6222"},
+ // {"price":"347.4","vol":"20979"},
+ // {"price":"347.3","vol":"15179"},
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ if (market['spot']) {
+ return this.parseOrderBook (data, undefined, 'buys', 'sells', 'price', 'amount');
+ } else if (market['swap'] || market['future']) {
+ return this.parseOrderBook (data, undefined, 'buys', 'sells', 'price', 'vol');
+ }
}
parseTrade (trade, market = undefined) {
//
- // fetchTrades (public)
+ // public fetchTrades spot
//
// {
- // "amount":"2.29275119",
- // "price":"0.021858",
- // "count":"104.8930",
- // "order_time":1563997286061,
+ // "amount":"0.005703",
+ // "order_time":1599652045394,
+ // "price":"0.034029",
+ // "count":"0.1676",
// "type":"sell"
// }
//
- // fetchMyTrades (private)
+ // public fetchTrades contract, private fetchMyTrades contract
//
// {
- // active: true,
- // amount: '0.2000',
- // entrustType: 1,
- // entrust_id: 979648824,
- // fees: '0.0000085532',
- // price: '0.021383',
- // symbol: 'ETH_BTC',
- // timestamp: 1574343514000,
- // trade_id: 329418828
- // },
+ // "order_id":109159616160,
+ // "trade_id":109159616197,
+ // "contract_id":2,
+ // "deal_price":"347.6",
+ // "deal_vol":"5623",
+ // "make_fee":"-5.8636644",
+ // "take_fee":"9.772774",
+ // "created_at":"2020-09-09T11:49:50.749170536Z",
+ // "way":1,
+ // "fluctuation":"0"
+ // }
//
- const id = this.safeString (trade, 'trade_id');
- const timestamp = this.safeInteger2 (trade, 'timestamp', 'order_time');
+ // private fetchMyTrades spot
+ //
+ // {
+ // "detail_id":256348632,
+ // "order_id":2147484350,
+ // "symbol":"BTC_USDT",
+ // "create_time":1590462303000,
+ // "side":"buy",
+ // "fees":"0.00001350",
+ // "fee_coin_name":"BTC",
+ // "notional":"88.00000000",
+ // "price_avg":"8800.00",
+ // "size":"0.01000",
+ // "exec_type":"M"
+ // }
+ //
+ const id = this.safeString2 (trade, 'trade_id', 'detail_id');
+ let timestamp = this.safeInteger2 (trade, 'order_time', 'create_time');
+ if (timestamp === undefined) {
+ timestamp = this.parse8601 (this.safeString (trade, 'created_at'));
+ }
const type = undefined;
- let side = this.safeStringLower (trade, 'type');
- if ((side === undefined) && ('entrustType' in trade)) {
- side = trade['entrustType'] ? 'sell' : 'buy';
- }
- const price = this.safeFloat (trade, 'price');
- const amount = this.safeFloat (trade, 'amount');
- let cost = undefined;
- if (price !== undefined) {
- if (amount !== undefined) {
- cost = amount * price;
- }
- }
- const orderId = this.safeInteger (trade, 'entrust_id');
- const marketId = this.safeString (trade, 'symbol');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
+ const way = this.safeInteger (trade, 'way');
+ let side = this.safeStringLower2 (trade, 'type', 'side');
+ if ((side === undefined) && (way !== undefined)) {
+ if (way < 5) {
+ side = 'buy';
} else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
+ side = 'sell';
}
}
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ let takerOrMaker = undefined;
+ const execType = this.safeString (trade, 'exec_type');
+ if (execType !== undefined) {
+ takerOrMaker = (execType === 'M') ? 'maker' : 'taker';
}
+ let price = this.safeFloat2 (trade, 'price', 'deal_price');
+ price = this.safeFloat (trade, 'price_avg', price);
+ let amount = this.safeFloat2 (trade, 'amount', 'deal_vol');
+ amount = this.safeFloat (trade, 'size', amount);
+ let cost = this.safeFloat2 (trade, 'count', 'notional');
+ if ((cost === undefined) && (price !== undefined) && (amount !== undefined)) {
+ cost = amount * price;
+ }
+ const orderId = this.safeInteger (trade, 'order_id');
+ const marketId = this.safeString2 (trade, 'contract_id', 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
const feeCost = this.safeFloat (trade, 'fees');
let fee = undefined;
if (feeCost !== undefined) {
- let feeCurrencyCode = undefined;
- if (market !== undefined) {
+ const feeCurrencyId = this.safeString (trade, 'fee_coin_name');
+ let feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ if ((feeCurrencyCode === undefined) && (market !== undefined)) {
feeCurrencyCode = (side === 'buy') ? market['base'] : market['quote'];
}
fee = {
@@ -18369,7 +21636,7 @@ module.exports = class bitmart extends Exchange {
'price': price,
'amount': amount,
'cost': cost,
- 'takerOrMaker': undefined,
+ 'takerOrMaker': takerOrMaker,
'fee': fee,
};
}
@@ -18380,19 +21647,193 @@ module.exports = class bitmart extends Exchange {
const request = {
'symbol': market['id'],
};
- const response = await this.publicGetSymbolsSymbolTrades (this.extend (request, params));
+ let method = undefined;
+ if (market['spot']) {
+ request['symbol'] = market['id'];
+ method = 'publicSpotGetSymbolsTrades';
+ } else if (market['swap'] || market['future']) {
+ method = 'publicContractGetTrades';
+ request['contractID'] = market['id'];
+ }
+ const response = await this[method] (this.extend (request, params));
//
- // [
- // {
- // "amount":"2.29275119",
- // "price":"0.021858",
- // "count":"104.8930",
- // "order_time":1563997286061,
- // "type":"sell"
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"222d74c0-8f6d-49d9-8e1b-98118c50eeba",
+ // "data":{
+ // "trades":[
+ // {
+ // "amount":"0.005703",
+ // "order_time":1599652045394,
+ // "price":"0.034029",
+ // "count":"0.1676",
+ // "type":"sell"
+ // },
+ // ]
// }
- // ]
+ // }
//
- return this.parseTrades (response, market, since, limit);
+ // contract
+ //
+ // {
+ // "errno":"OK",
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"782bc746-b86e-43bf-8d1a-c68b479c9bdd",
+ // "data":{
+ // "trades":[
+ // {
+ // "order_id":109159616160,
+ // "trade_id":109159616197,
+ // "contract_id":2,
+ // "deal_price":"347.6",
+ // "deal_vol":"5623",
+ // "make_fee":"-5.8636644",
+ // "take_fee":"9.772774",
+ // "created_at":"2020-09-09T11:49:50.749170536Z",
+ // "way":1,
+ // "fluctuation":"0"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'trades', []);
+ return this.parseTrades (trades, market, since, limit);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // spot
+ //
+ // {
+ // "last_price":"0.034987",
+ // "timestamp":1598787420,
+ // "volume":"1.0198",
+ // "open":"0.035007",
+ // "close":"0.034987",
+ // "high":"0.035007",
+ // "low":"0.034986"
+ // }
+ //
+ // contract
+ //
+ // {
+ // "low":"404.4",
+ // "high":"404.4",
+ // "open":"404.4",
+ // "close":"404.4",
+ // "last_price":"404.4",
+ // "avg_price":"404.4",
+ // "volume":"7670",
+ // "timestamp":1598758441,
+ // "rise_fall_rate":"0",
+ // "rise_fall_value":"0",
+ // "base_coin_volume":"76.7",
+ // "quote_coin_volume":"31017.48"
+ // }
+ //
+ return [
+ this.safeTimestamp (ohlcv, 'timestamp'),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'volume'),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = market['type'];
+ let method = undefined;
+ const request = {};
+ const duration = this.parseTimeframe (timeframe);
+ if (type === 'spot') {
+ method = 'publicSpotGetSymbolsKline';
+ request['symbol'] = market['id'];
+ request['step'] = this.timeframes[timeframe];
+ // the exchange will return an empty array if more than 500 candles is requested
+ const maxLimit = 500;
+ if (limit === undefined) {
+ limit = maxLimit;
+ }
+ limit = Math.min (maxLimit, limit);
+ if (since === undefined) {
+ const end = parseInt (this.milliseconds () / 1000);
+ const start = end - limit * duration;
+ request['from'] = start;
+ request['to'] = end;
+ } else {
+ const start = parseInt (since / 1000);
+ const end = this.sum (start, limit * duration);
+ request['from'] = start;
+ request['to'] = end;
+ }
+ } else if ((type === 'swap') || (type === 'future')) {
+ method = 'publicContractGetQuote';
+ request['contractID'] = market['id'];
+ const defaultLimit = 500;
+ if (limit === undefined) {
+ limit = defaultLimit;
+ }
+ if (since === undefined) {
+ const end = parseInt (this.milliseconds () / 1000);
+ const start = end - limit * duration;
+ request['startTime'] = start;
+ request['endTime'] = end;
+ } else {
+ const start = parseInt (since / 1000);
+ const end = this.sum (start, limit * duration);
+ request['startTime'] = start;
+ request['endTime'] = end;
+ }
+ request['unit'] = this.timeframes[timeframe];
+ request['resolution'] = 'M';
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"80d86378-ab4e-4c70-819e-b42146cf87ad",
+ // "data":{
+ // "klines":[
+ // {"last_price":"0.034987","timestamp":1598787420,"volume":"1.0198","open":"0.035007","close":"0.034987","high":"0.035007","low":"0.034986"},
+ // {"last_price":"0.034986","timestamp":1598787480,"volume":"0.3959","open":"0.034982","close":"0.034986","high":"0.034986","low":"0.034980"},
+ // {"last_price":"0.034978","timestamp":1598787540,"volume":"0.3259","open":"0.034987","close":"0.034978","high":"0.034987","low":"0.034977"},
+ // ]
+ // }
+ // }
+ //
+ // swap
+ //
+ // {
+ // "errno":"OK",
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"32965074-5804-4655-b693-e953e36026a0",
+ // "data":[
+ // {"low":"404.4","high":"404.4","open":"404.4","close":"404.4","last_price":"404.4","avg_price":"404.4","volume":"7670","timestamp":1598758441,"rise_fall_rate":"0","rise_fall_value":"0","base_coin_volume":"76.7","quote_coin_volume":"31017.48"},
+ // {"low":"404.1","high":"404.4","open":"404.4","close":"404.1","last_price":"404.1","avg_price":"404.15881086","volume":"12076","timestamp":1598758501,"rise_fall_rate":"-0.000741839762611276","rise_fall_value":"-0.3","base_coin_volume":"120.76","quote_coin_volume":"48806.2179994536"},
+ // {"low":"404","high":"404.3","open":"404.1","close":"404","last_price":"404","avg_price":"404.08918918","volume":"740","timestamp":1598758561,"rise_fall_rate":"-0.000247463499133878","rise_fall_value":"-0.1","base_coin_volume":"7.4","quote_coin_volume":"2990.259999932"},
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ if (Array.isArray (data)) {
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
+ } else {
+ const klines = this.safeValue (data, 'klines', []);
+ return this.parseOHLCVs (klines, market, timeframe, since, limit);
+ }
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -18401,114 +21842,236 @@ module.exports = class bitmart extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
- // limit is required, must be in the range (0, 50)
- const maxLimit = 50;
- limit = (limit === undefined) ? maxLimit : Math.min (limit, maxLimit);
- const request = {
- 'symbol': market['id'],
- 'offset': 0, // current page, starts from 0
- 'limit': limit, // required
- };
- const response = await this.privateGetTrades (this.extend (request, params));
+ let method = undefined;
+ const request = {};
+ if (market['spot']) {
+ request['symbol'] = market['id'];
+ request['offset'] = 1;
+ if (limit === undefined) {
+ limit = 100; // max 100
+ }
+ request['limit'] = limit;
+ method = 'privateSpotGetTrades';
+ } else if (market['swap'] || market['future']) {
+ request['contractID'] = market['id'];
+ // request['offset'] = 1;
+ if (limit !== undefined) {
+ request['size'] = limit; // max 60
+ }
+ method = 'privateContractGetUserTrades';
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
//
// {
- // "total_trades": 216,
- // "total_pages": 22,
- // "current_page": 0,
- // "trades": [
- // {
- // "symbol": "BMX_ETH",
- // "amount": "1.0",
- // "fees": "0.0005000000",
- // "trade_id": 2734956,
- // "price": "0.00013737",
- // "active": true,
- // "entrust_id": 5576623,
- // "timestamp": 1545292334000
- // },
- // ]
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"a06a5c53-8e6f-42d6-8082-2ff4718d221c",
+ // "data":{
+ // "current_page":1,
+ // "trades":[
+ // {
+ // "detail_id":256348632,
+ // "order_id":2147484350,
+ // "symbol":"BTC_USDT",
+ // "create_time":1590462303000,
+ // "side":"buy",
+ // "fees":"0.00001350",
+ // "fee_coin_name":"BTC",
+ // "notional":"88.00000000",
+ // "price_avg":"8800.00",
+ // "size":"0.01000",
+ // "exec_type":"M"
+ // },
+ // ]
+ // }
// }
//
- const trades = this.safeValue (response, 'trades', []);
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "trades": [
+ // {
+ // "order_id": 10116361,
+ // "trade_id": 10116363,
+ // "contract_id": 1,
+ // "deal_price": "16",
+ // "deal_vol": "10",
+ // "make_fee": "0.04",
+ // "take_fee": "0.12",
+ // "created_at": null,
+ // "way": 5,
+ // "fluctuation": "0"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'trades', []);
return this.parseTrades (trades, market, since, limit);
}
async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'entrust_id': id,
- };
- return await this.fetchMyTrades (symbol, since, limit, this.extend (request, params));
- }
-
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
- return [
- this.safeInteger (ohlcv, 'timestamp'),
- this.safeFloat (ohlcv, 'open_price'),
- this.safeFloat (ohlcv, 'highest_price'),
- this.safeFloat (ohlcv, 'lowest_price'),
- this.safeFloat (ohlcv, 'current_price'),
- this.safeFloat (ohlcv, 'volume'),
- ];
- }
-
- async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
- if (since === undefined && limit === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchOHLCV requires either a `since` argument or a `limit` argument (or both)');
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrderTrades requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
- const periodInSeconds = this.parseTimeframe (timeframe);
- const duration = periodInSeconds * limit * 1000;
- let to = this.milliseconds ();
- if (since === undefined) {
- since = to - duration;
- } else {
- to = this.sum (since, duration);
+ let method = undefined;
+ const request = {};
+ if (market['spot']) {
+ request['symbol'] = market['id'];
+ request['order_id'] = id;
+ method = 'privateSpotGetTrades';
+ } else if (market['swap'] || market['future']) {
+ request['contractID'] = market['id'];
+ request['orderID'] = id;
+ method = 'privateContractGetOrderTrades';
}
- const request = {
- 'symbol': market['id'],
- 'from': since, // start time of k-line data (in milliseconds, required)
- 'to': to, // end time of k-line data (in milliseconds, required)
- 'step': this.timeframes[timeframe], // steps of sampling (in minutes, default 1 minute, optional)
- };
- const response = await this.publicGetSymbolsSymbolKline (this.extend (request, params));
+ const response = await this[method] (this.extend (request, params));
//
- // [
- // {
- // "timestamp":1525761000000,
- // "open_price":"0.010130",
- // "highest_price":"0.010130",
- // "lowest_price":"0.010130",
- // "current_price":"0.010130",
- // "volume":"0.000000"
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"a06a5c53-8e6f-42d6-8082-2ff4718d221c",
+ // "data":{
+ // "current_page":1,
+ // "trades":[
+ // {
+ // "detail_id":256348632,
+ // "order_id":2147484350,
+ // "symbol":"BTC_USDT",
+ // "create_time":1590462303000,
+ // "side":"buy",
+ // "fees":"0.00001350",
+ // "fee_coin_name":"BTC",
+ // "notional":"88.00000000",
+ // "price_avg":"8800.00",
+ // "size":"0.01000",
+ // "exec_type":"M"
+ // },
+ // ]
// }
- // ]
+ // }
//
- return this.parseOHLCVs (response, market, timeframe, since, limit);
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "trades": [
+ // {
+ // "order_id": 10116361,
+ // "trade_id": 10116363,
+ // "contract_id": 1,
+ // "deal_price": "16",
+ // "deal_vol": "10",
+ // "make_fee": "0.04",
+ // "take_fee": "0.12",
+ // "created_at": null,
+ // "way": 5,
+ // "fluctuation": "0"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'trades', []);
+ return this.parseTrades (trades, market, since, limit);
}
async fetchBalance (params = {}) {
await this.loadMarkets ();
- const balances = await this.privateGetWallet (params);
+ let method = undefined;
+ const options = this.safeValue (this.options, 'fetchBalance', {});
+ const defaultType = this.safeString (this.options, 'defaultType', 'spot');
+ let type = this.safeString (options, 'type', defaultType);
+ type = this.safeString (params, 'type', type);
+ params = this.omit (params, 'type');
+ if (type === 'spot') {
+ method = 'privateSpotGetWallet';
+ } else if (type === 'account') {
+ method = 'privateAccountGetWallet';
+ } else if ((type === 'swap') || (type === 'future') || (type === 'contract')) {
+ method = 'privateContractGetAccounts';
+ }
+ const response = await this[method] (params);
//
- // [
- // {
- // "name":"Bitcoin",
- // "available":"0.0000000000",
- // "frozen":"0.0000000000",
- // "id":"BTC"
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"39069916-72f9-44c7-acde-2ad5afd21cad",
+ // "data":{
+ // "wallet":[
+ // {"id":"BTC","name":"Bitcoin","available":"0.00000062","frozen":"0.00000000"},
+ // {"id":"ETH","name":"Ethereum","available":"0.00002277","frozen":"0.00000000"},
+ // {"id":"BMX","name":"BitMart Token","available":"0.00000000","frozen":"0.00000000"}
+ // ]
// }
- // ]
+ // }
//
- const result = { 'info': balances };
- for (let i = 0; i < balances.length; i++) {
- const balance = balances[i];
- const currencyId = this.safeString (balance, 'id');
+ // account
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"5c3b7fc7-93b2-49ef-bb59-7fdc56915b59",
+ // "data":{
+ // "wallet":[
+ // {"currency":"BTC","name":"Bitcoin","available":"0.00000062","frozen":"0.00000000"},
+ // {"currency":"ETH","name":"Ethereum","available":"0.00002277","frozen":"0.00000000"}
+ // ]
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "accounts": [
+ // {
+ // "account_id": 10,
+ // "coin_code": "USDT",
+ // "freeze_vol": "1201.8",
+ // "available_vol": "8397.65",
+ // "cash_vol": "0",
+ // "realised_vol": "-0.5",
+ // "unrealised_vol": "-0.5",
+ // "earnings_vol": "-0.5",
+ // "created_at": "2018-07-13T16:48:49+08:00",
+ // "updated_at": "2018-07-13T18:34:45.900387+08:00"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const wallet = this.safeValue2 (data, 'wallet', 'accounts', []);
+ const result = { 'info': response };
+ for (let i = 0; i < wallet.length; i++) {
+ const balance = wallet[i];
+ let currencyId = this.safeString2 (balance, 'id', 'currency');
+ currencyId = this.safeString (balance, 'coind_code', currencyId);
const code = this.safeCurrencyCode (currencyId);
const account = this.account ();
- account['free'] = this.safeFloat (balance, 'available');
- account['used'] = this.safeFloat (balance, 'frozen');
+ account['free'] = this.safeFloat2 (balance, 'available', 'available_vol');
+ account['used'] = this.safeFloat2 (balance, 'frozen', 'freeze_vol');
result[code] = account;
}
return this.parseBalance (result);
@@ -18519,70 +22082,111 @@ module.exports = class bitmart extends Exchange {
// createOrder
//
// {
- // "entrust_id":1223181
+ // "order_id": 2707217580
// }
//
// cancelOrder
//
- // {}
+ // '2707217580' // order id
//
- // fetchOrder, fetchOrdersByStatus, fetchOpenOrders, fetchClosedOrders
+ // spot fetchOrder, fetchOrdersByStatus, fetchOpenOrders, fetchClosedOrders
//
// {
- // "entrust_id":1223181,
- // "symbol":"BMX_ETH",
- // "timestamp":1528060666000,
- // "side":"buy",
- // "price":"1.000000",
- // "fees":"0.1",
- // "original_amount":"1",
- // "executed_amount":"1",
- // "remaining_amount":"0",
- // "status":3
+ // "order_id":1736871726781,
+ // "symbol":"BTC_USDT",
+ // "create_time":1591096004000,
+ // "side":"sell",
+ // "type":"market",
+ // "price":"0.00",
+ // "price_avg":"0.00",
+ // "size":"0.02000",
+ // "notional":"0.00000000",
+ // "filled_notional":"0.00000000",
+ // "filled_size":"0.00000",
+ // "status":"8"
// }
//
- const id = this.safeString (order, 'entrust_id');
- const timestamp = this.milliseconds ();
- const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let symbol = undefined;
- const marketId = this.safeString (order, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ // contract fetchOrder, fetchOrdersByStatus, fetchOpenOrders, fetchClosedOrders, fetchOrders
+ //
+ // {
+ // "order_id": 10539098,
+ // "contract_id": 1,
+ // "position_id": 10539088,
+ // "account_id": 10,
+ // "price": "16",
+ // "vol": "1",
+ // "done_avg_price": "16",
+ // "done_vol": "1",
+ // "way": 3,
+ // "category": 1,
+ // "open_type": 2,
+ // "make_fee": "0.00025",
+ // "take_fee": "0.012",
+ // "origin": "",
+ // "created_at": "2018-07-23T11:55:56.715305Z",
+ // "finished_at": "2018-07-23T11:55:56.763941Z",
+ // "status": 4,
+ // "errno": 0
+ // }
+ //
+ let id = undefined;
+ if (typeof order === 'string') {
+ id = order;
+ order = {};
}
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
+ id = this.safeString (order, 'order_id', id);
+ let timestamp = this.parse8601 (this.safeString (order, 'created_at'));
+ timestamp = this.safeInteger (order, 'create_time', timestamp);
+ const marketId = this.safeString2 (order, 'symbol', 'contract_id');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ let status = undefined;
+ if (market !== undefined) {
+ status = this.parseOrderStatusByType (market['type'], this.safeString (order, 'status'));
}
- const price = this.safeFloat (order, 'price');
- const amount = this.safeFloat (order, 'original_amount');
+ let price = this.safeFloat (order, 'price');
+ let average = this.safeFloat2 (order, 'price_avg', 'done_avg_price');
+ const amount = this.safeFloat2 (order, 'size', 'vol');
let cost = undefined;
- let filled = this.safeFloat (order, 'executed_amount');
- let remaining = this.safeFloat (order, 'remaining_amount');
+ let filled = this.safeFloat2 (order, 'filled_size', 'done_vol');
+ let remaining = undefined;
if (amount !== undefined) {
if (remaining !== undefined) {
if (filled === undefined) {
- filled = amount - remaining;
+ filled = Math.max (0, amount - remaining);
}
}
if (filled !== undefined) {
if (remaining === undefined) {
- remaining = amount - filled;
+ remaining = Math.max (0, amount - filled);
}
if (cost === undefined) {
- if (price !== undefined) {
- cost = price * filled;
+ if (average !== undefined) {
+ cost = average * filled;
}
}
}
}
- const side = this.safeString (order, 'side');
- const type = undefined;
+ let side = this.safeString (order, 'side');
+ // 1 = Open long
+ // 2 = Close short
+ // 3 = Close long
+ // 4 = Open short
+ side = this.safeString (order, 'way', side);
+ const category = this.safeInteger (order, 'category');
+ let type = this.safeString (order, 'type');
+ if (category === 1) {
+ type = 'limit';
+ } else if (category === 2) {
+ type = 'market';
+ }
+ if (type === 'market') {
+ if (price === 0.0) {
+ price = undefined;
+ }
+ if (average === 0.0) {
+ average = undefined;
+ }
+ }
return {
'id': id,
'clientOrderId': undefined,
@@ -18592,11 +22196,13 @@ module.exports = class bitmart extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
- 'cost': undefined,
- 'average': undefined,
+ 'cost': cost,
+ 'average': average,
'filled': filled,
'remaining': remaining,
'status': status,
@@ -18605,52 +22211,154 @@ module.exports = class bitmart extends Exchange {
};
}
- parseOrderStatus (status) {
- const statuses = {
- '0': 'all',
- '1': 'open',
- '2': 'open',
- '3': 'closed',
- '4': 'canceled',
- '5': 'open',
- '6': 'closed',
+ parseOrderStatusByType (type, status) {
+ const statusesByType = {
+ 'spot': {
+ '1': 'failed', // Order failure
+ '2': 'open', // Placing order
+ '3': 'failed', // Order failure, Freeze failure
+ '4': 'open', // Order success, Pending for fulfilment
+ '5': 'open', // Partially filled
+ '6': 'closed', // Fully filled
+ '7': 'canceling', // Canceling
+ '8': 'canceled', // Canceled
+ },
+ 'swap': {
+ '1': 'open', // Submitting
+ '2': 'open', // Commissioned
+ '4': 'closed', // Completed
+ },
};
+ const statuses = this.safeValue (statusesByType, type, {});
return this.safeString (statuses, status, status);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- if (type !== 'limit') {
- throw new ExchangeError (this.id + ' allows limit orders only');
- }
await this.loadMarkets ();
const market = this.market (symbol);
- const request = {
- 'symbol': market['id'],
- 'side': side.toLowerCase (),
- 'amount': this.amountToPrecision (symbol, amount),
- 'price': this.priceToPrecision (symbol, price),
- };
- const response = await this.privatePostOrders (this.extend (request, params));
+ const request = {};
+ let method = undefined;
+ if (market['spot']) {
+ request['symbol'] = market['id'];
+ request['side'] = side;
+ request['type'] = type;
+ method = 'privateSpotPostSubmitOrder';
+ if (type === 'limit') {
+ request['size'] = this.amountToPrecision (symbol, amount);
+ request['price'] = this.priceToPrecision (symbol, price);
+ } else if (type === 'market') {
+ // for market buy it requires the amount of quote currency to spend
+ if (side === 'buy') {
+ let notional = this.safeFloat (params, 'notional');
+ const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true);
+ if (createMarketBuyOrderRequiresPrice) {
+ if (price !== undefined) {
+ if (notional === undefined) {
+ notional = amount * price;
+ }
+ } else if (notional === undefined) {
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument or in the 'notional' extra parameter (the exchange-specific behaviour)");
+ }
+ } else {
+ notional = (notional === undefined) ? amount : notional;
+ }
+ const precision = market['precision']['price'];
+ request['notional'] = this.decimalToPrecision (notional, TRUNCATE, precision, this.precisionMode);
+ } else if (side === 'sell') {
+ request['size'] = this.amountToPrecision (symbol, amount);
+ }
+ }
+ } else if (market['swap'] || market['future']) {
+ method = 'privateContractPostSubmitOrder';
+ request['contractID'] = market['id'];
+ if (type === 'limit') {
+ request['category'] = 1;
+ } else if (type === 'market') {
+ request['category'] = 2;
+ }
+ request['way'] = side; // 1 = open long, 2 = close short, 3 = close long, 4 = open short
+ request['custom_id'] = this.nonce ();
+ request['open_type'] = 1; // 1 = cross margin, 2 = fixed margin
+ request['leverage'] = 1; // must meet the effective range of leverage configured in the contract
+ request['price'] = this.priceToPrecision (symbol, price);
+ request['vol'] = this.amountToPrecision (symbol, amount);
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot and contract
//
// {
- // "entrust_id":1223181
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "order_id": 2707217580
+ // }
// }
//
- return this.parseOrder (response, market);
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
await this.loadMarkets ();
- const intId = parseInt (id);
- const request = {
- 'id': intId,
- 'entrust_id': intId,
- };
- const response = await this.privateDeleteOrdersId (this.extend (request, params));
+ const market = this.market (symbol);
+ const request = {};
+ let method = undefined;
+ if (market['spot']) {
+ method = 'privateSpotPostCancelOrder';
+ request['order_id'] = parseInt (id);
+ request['symbol'] = market['id'];
+ } else if (market['swap'] || market['future']) {
+ method = 'privateContractPostCancelOrders';
+ request['contractID'] = market['id'];
+ request['orders'] = [ parseInt (id) ];
+ }
+ const response = await this[method] (this.extend (request, params));
//
- // responds with an empty object {}
+ // spot
//
- return this.parseOrder (response);
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "result": true
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "succeed": [
+ // 2707219612
+ // ],
+ // "failed": []
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const succeeded = this.safeValue (data, 'succeed');
+ if (succeeded !== undefined) {
+ id = this.safeString (succeeded, 0);
+ if (id === undefined) {
+ throw new InvalidOrder (this.id + ' cancelOrder failed to cancel ' + symbol + ' order id ' + id);
+ }
+ } else {
+ const result = this.safeValue (data, 'result');
+ if (!result) {
+ throw new InvalidOrder (this.id + ' cancelOrder ' + symbol + ' order id ' + id + ' is filled or canceled');
+ }
+ }
+ const order = this.parseOrder (id, market);
+ return this.extend (order, { 'id': id });
}
async cancelAllOrders (symbol = undefined, params = {}) {
@@ -18663,13 +22371,67 @@ module.exports = class bitmart extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
+ if (!market['spot']) {
+ throw new NotSupported (this.id + ' cancelAllOrders does not support ' + market['type'] + ' orders, only spot orders are accepted');
+ }
const request = {
'symbol': market['id'],
'side': side, // 'buy' or 'sell'
};
- const response = await this.privateDeleteOrders (this.extend (request, params));
+ const response = await this.privateSpotPostCancelOrders (this.extend (request, params));
//
- // responds with an empty object {}
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {}
+ // }
+ //
+ return response;
+ }
+
+ async cancelOrders (ids, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' canelOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ if (!market['spot']) {
+ throw new NotSupported (this.id + ' cancelOrders does not support ' + market['type'] + ' orders, only contract orders are accepted');
+ }
+ const orders = [];
+ for (let i = 0; i < ids.length; i++) {
+ orders.push (parseInt (ids[i]));
+ }
+ const request = {
+ 'orders': orders,
+ };
+ const response = await this.privateContractPostCancelOrders (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "result": true
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "succeed": [
+ // 2707219612
+ // ],
+ // "failed": []
+ // }
+ // }
//
return response;
}
@@ -18680,77 +22442,425 @@ module.exports = class bitmart extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
- if (limit === undefined) {
- limit = 500; // default 500, max 1000
+ const request = {};
+ let method = undefined;
+ if (market['spot']) {
+ method = 'privateSpotGetOrders';
+ request['symbol'] = market['id'];
+ request['offset'] = 1; // max offset * limit < 500
+ request['limit'] = 100; // max limit is 100
+ // 1 = Order failure
+ // 2 = Placing order
+ // 3 = Order failure, Freeze failure
+ // 4 = Order success, Pending for fulfilment
+ // 5 = Partially filled
+ // 6 = Fully filled
+ // 7 = Canceling
+ // 8 = Canceled
+ // 9 = Outstanding (4 and 5)
+ // 10 = 6 and 8
+ if (status === 'open') {
+ request['status'] = 9;
+ } else if (status === 'closed') {
+ request['status'] = 6;
+ } else {
+ request['status'] = status;
+ }
+ } else if (market['swap'] || market['future']) {
+ method = 'privateContractGetUserOrders';
+ request['contractID'] = market['id'];
+ // request['offset'] = 1;
+ if (limit !== undefined) {
+ request['size'] = limit; // max 60
+ }
+ // 0 = All
+ // 1 = Submitting
+ // 2 = Commissioned
+ // 3 = 1 and 2
+ // 4 = Completed
+ if (status === 'open') {
+ request['status'] = 3;
+ } else if (status === 'closed') {
+ request['status'] = 4;
+ } else {
+ request['status'] = status;
+ }
}
- const request = {
- 'symbol': market['id'],
- 'status': status,
- 'offset': 0, // current page, starts from 0
- 'limit': limit,
- };
- const response = await this.privateGetOrders (this.extend (request, params));
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
//
// {
- // "orders":[
- // {
- // "entrust_id":1223181,
- // "symbol":"BMX_ETH",
- // "timestamp":1528060666000,
- // "side":"buy",
- // "price":"1.000000",
- // "fees":"0.1",
- // "original_amount":"1",
- // "executed_amount":"1",
- // "remaining_amount":"0",
- // "status":3
- // }
- // ],
- // "total_pages":1,
- // "total_orders":1,
- // "current_page":0,
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"70e7d427-7436-4fb8-8cdd-97e1f5eadbe9",
+ // "data":{
+ // "current_page":1,
+ // "orders":[
+ // {
+ // "order_id":2147601241,
+ // "symbol":"BTC_USDT",
+ // "create_time":1591099963000,
+ // "side":"sell",
+ // "type":"limit",
+ // "price":"9000.00",
+ // "price_avg":"0.00",
+ // "size":"1.00000",
+ // "notional":"9000.00000000",
+ // "filled_notional":"0.00000000",
+ // "filled_size":"0.00000",
+ // "status":"4"
+ // }
+ // ]
+ // }
// }
//
- const orders = this.safeValue (response, 'orders', []);
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "orders": [
+ // {
+ // "order_id": 10284160,
+ // "contract_id": 1,
+ // "price": "8",
+ // "vol": "4",
+ // "done_avg_price": "0",
+ // "done_vol": "0",
+ // "way": 1,
+ // "category": 1,
+ // "open_type": 2,
+ // "make_fee": "0",
+ // "take_fee": "0",
+ // "origin": "",
+ // "created_at": "2018-07-17T07:24:13.410507Z",
+ // "finished_at": null,
+ // "status": 2,
+ // "errno": 0
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const orders = this.safeValue (data, 'orders', []);
return this.parseOrders (orders, market, since, limit);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- // 5 = pending & partially filled orders
- return await this.fetchOrdersByStatus (5, symbol, since, limit, params);
+ return await this.fetchOrdersByStatus ('open', symbol, since, limit, params);
}
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- // 3 = closed orders
- return await this.fetchOrdersByStatus (3, symbol, since, limit, params);
+ return await this.fetchOrdersByStatus ('closed', symbol, since, limit, params);
}
- async fetchCanceledOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- // 4 = canceled orders
- return await this.fetchOrdersByStatus (4, symbol, since, limit, params);
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ if (!(market['swap'] || market['future'])) {
+ throw new NotSupported (this.id + ' fetchOrders does not support ' + market['type'] + ' markets, only contracts are supported');
+ }
+ return await this.fetchOrdersByStatus (0, symbol, since, limit, params);
}
async fetchOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ }
await this.loadMarkets ();
- const request = {
- 'id': id,
- };
- const response = await this.privateGetOrdersId (this.extend (request, params));
+ const request = {};
+ const market = this.market (symbol);
+ let method = undefined;
+ if (typeof id !== 'string') {
+ id = id.toString ();
+ }
+ if (market['spot']) {
+ request['symbol'] = market['id'];
+ request['order_id'] = id;
+ method = 'privateSpotGetOrderDetail';
+ } else if (market['swap'] || market['future']) {
+ request['contractID'] = market['id'];
+ request['orderID'] = id;
+ method = 'privateContractGetUserOrderInfo';
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
//
// {
- // "entrust_id":1223181,
- // "symbol":"BMX_ETH",
- // "timestamp":1528060666000,
- // "side":"buy",
- // "price":"1.000000",
- // "fees":"0.1",
- // "original_amount":"1",
- // "executed_amount":"1",
- // "remaining_amount":"0",
- // "status":3
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"a27c2cb5-ead4-471d-8455-1cfeda054ea6",
+ // "data": {
+ // "order_id":1736871726781,
+ // "symbol":"BTC_USDT",
+ // "create_time":1591096004000,
+ // "side":"sell",
+ // "type":"market",
+ // "price":"0.00",
+ // "price_avg":"0.00",
+ // "size":"0.02000",
+ // "notional":"0.00000000",
+ // "filled_notional":"0.00000000",
+ // "filled_size":"0.00000",
+ // "status":"8"
+ // }
// }
//
- return this.parseOrder (response);
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "orders": [
+ // {
+ // "order_id": 10539098,
+ // "contract_id": 1,
+ // "position_id": 10539088,
+ // "account_id": 10,
+ // "price": "16",
+ // "vol": "1",
+ // "done_avg_price": "16",
+ // "done_vol": "1",
+ // "way": 3,
+ // "category": 1,
+ // "make_fee": "0.00025",
+ // "take_fee": "0.012",
+ // "origin": "",
+ // "created_at": "2018-07-23T11:55:56.715305Z",
+ // "finished_at": "2018-07-23T11:55:56.763941Z",
+ // "status": 4,
+ // "errno": 0
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ if ('orders' in data) {
+ const orders = this.safeValue (data, 'orders', []);
+ const firstOrder = this.safeValue (orders, 0);
+ if (firstOrder === undefined) {
+ throw new OrderNotFound (this.id + ' fetchOrder could not find ' + symbol + ' order id ' + id);
+ }
+ return this.parseOrder (firstOrder, market);
+ } else {
+ return this.parseOrder (data, market);
+ }
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privateAccountGetDepositAddress (this.extend (request, params));
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"0e6edd79-f77f-4251-abe5-83ba75d06c1a",
+ // "data":{
+ // "currency":"USDT-TRC20",
+ // "chain":"USDT-TRC20",
+ // "address":"TGR3ghy2b5VLbyAYrmiE15jasR6aPHTvC5",
+ // "address_memo":""
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const address = this.safeString (data, 'address');
+ const tag = this.safeString (data, 'address_memo');
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': response,
+ };
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ 'amount': amount,
+ 'destination': 'To Digital Address', // To Digital Address, To Binance, To OKEX
+ 'address': address,
+ };
+ if (tag !== undefined) {
+ request['address_memo'] = tag;
+ }
+ const response = await this.privateAccountPostWithdrawApply (this.extend (request, params));
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "withdraw_id": "121212"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const transaction = this.parseTransaction (data, currency);
+ return this.extend (transaction, {
+ 'code': code,
+ 'address': address,
+ 'tag': tag,
+ });
+ }
+
+ async fetchTransactionsByType (type, code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ if (limit === undefined) {
+ limit = 50; // max 50
+ }
+ const request = {
+ 'operation_type': type, // deposit or withdraw
+ 'offset': 1,
+ 'limit': limit,
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currenc (code);
+ request['currency'] = currency['id'];
+ }
+ const response = await this.privateAccountGetDepositWithdrawHistory (this.extend (request, params));
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"142bf92a-fc50-4689-92b6-590886f90b97",
+ // "data":{
+ // "records":[
+ // {
+ // "withdraw_id":"1679952",
+ // "deposit_id":"",
+ // "operation_type":"withdraw",
+ // "currency":"BMX",
+ // "apply_time":1588867374000,
+ // "arrival_amount":"59.000000000000",
+ // "fee":"1.000000000000",
+ // "status":0,
+ // "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
+ // "address_memo":"",
+ // "tx_id":""
+ // },
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const records = this.safeValue (data, 'records', []);
+ return this.parseTransactions (records, currency, since, limit);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsByType ('deposit', code, since, limit, params);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsByType ('withdraw', code, since, limit, params);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ '0': 'pending', // Create
+ '1': 'pending', // Submitted, waiting for withdrawal
+ '2': 'pending', // Processing
+ '3': 'ok', // Success
+ '4': 'canceled', // Cancel
+ '5': 'failed', // Fail
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // withdraw
+ //
+ // {
+ // "withdraw_id": "121212"
+ // }
+ //
+ // fetchDeposits, fetchWithdrawals
+ //
+ // {
+ // "withdraw_id":"1679952",
+ // "deposit_id":"",
+ // "operation_type":"withdraw",
+ // "currency":"BMX",
+ // "apply_time":1588867374000,
+ // "arrival_amount":"59.000000000000",
+ // "fee":"1.000000000000",
+ // "status":0,
+ // "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
+ // "address_memo":"",
+ // "tx_id":""
+ // }
+ //
+ let id = undefined;
+ const withdrawId = this.safeString (transaction, 'withdraw_id');
+ const depositId = this.safeString (transaction, 'deposit_id');
+ let type = undefined;
+ if ((withdrawId !== undefined) && (withdrawId !== '')) {
+ type = 'withdraw';
+ id = withdrawId;
+ } else if ((depositId !== undefined) && (depositId !== '')) {
+ type = 'deposit';
+ id = depositId;
+ }
+ const amount = this.safeFloat (transaction, 'arrival_amount');
+ const timestamp = this.safeInteger (transaction, 'tapply_timeime');
+ const currencyId = this.safeString (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const feeCost = this.safeFloat (transaction, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': code,
+ };
+ }
+ let txid = this.safeString (transaction, 'tx_id');
+ if (txid === '') {
+ txid = undefined;
+ }
+ const address = this.safeString (transaction, 'address');
+ const tag = this.safeString (transaction, 'address_memo');
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': code,
+ 'amount': amount,
+ 'address': address,
+ 'addressFrom': undefined,
+ 'addressTo': undefined,
+ 'tag': tag,
+ 'tagFrom': undefined,
+ 'tagTo': undefined,
+ 'status': status,
+ 'type': type,
+ 'updated': undefined,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': fee,
+ };
}
nonce () {
@@ -18758,45 +22868,49 @@ module.exports = class bitmart extends Exchange {
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- let url = this.urls['api'] + '/' + this.version + '/' + this.implodeParams (path, params);
- let query = this.omit (params, this.extractParams (path));
- if (api === 'public') {
+ const baseUrl = this.implodeParams (this.urls['api'], { 'hostname': this.hostname });
+ const access = this.safeString (api, 0);
+ const type = this.safeString (api, 1);
+ let url = baseUrl + '/' + type;
+ if (type !== 'system') {
+ url += '/' + this.version;
+ }
+ if (type === 'contract') {
+ url += '/' + 'ifcontract';
+ }
+ url += '/' + this.implodeParams (path, params);
+ const query = this.omit (params, this.extractParams (path));
+ if (type === 'system') {
if (Object.keys (query).length) {
+ // console.log (query);
url += '?' + this.urlencode (query);
}
- } else if (api === 'token') {
- this.checkRequiredCredentials ();
- body = this.urlencode (query);
- headers = {
- 'Content-Type': 'application/x-www-form-urlencoded',
- };
- } else {
- const nonce = this.nonce ();
- this.checkRequiredCredentials ();
- const token = this.safeString (this.options, 'accessToken');
- if (token === undefined) {
- throw new AuthenticationError (this.id + ' ' + path + ' endpoint requires an accessToken option or a prior call to signIn() method');
+ } else if (access === 'public') {
+ if (Object.keys (query).length) {
+ // console.log (query);
+ url += '?' + this.urlencode (query);
}
- const expires = this.safeInteger (this.options, 'expires');
- if (expires !== undefined) {
- if (nonce >= expires) {
- throw new AuthenticationError (this.id + ' accessToken expired, supply a new accessToken or call the signIn() method');
+ } else if (access === 'private') {
+ this.checkRequiredCredentials ();
+ const timestamp = this.milliseconds ().toString ();
+ let queryString = '';
+ headers = {
+ 'X-BM-KEY': this.apiKey,
+ 'X-BM-TIMESTAMP': timestamp,
+ };
+ if ((method === 'POST') || (method === 'PUT')) {
+ headers['Content-Type'] = 'application/json';
+ body = this.json (query);
+ queryString = body;
+ } else {
+ if (Object.keys (query).length) {
+ queryString = this.urlencode (query);
+ url += '?' + queryString;
}
}
- if (Object.keys (query).length) {
- url += '?' + this.urlencode (query);
- }
- headers = {
- 'Content-Type': 'application/json',
- 'X-BM-TIMESTAMP': nonce.toString (),
- 'X-BM-AUTHORIZATION': 'Bearer ' + token,
- };
- if (method !== 'GET') {
- query = this.keysort (query);
- body = this.json (query);
- const message = this.urlencode (query);
- headers['X-BM-SIGNATURE'] = this.hmac (this.encode (message), this.encode (this.secret), 'sha256');
- }
+ const auth = timestamp + '#' + this.uid + '#' + queryString;
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret));
+ headers['X-BM-SIGN'] = signature;
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
@@ -18806,20 +22920,23 @@ module.exports = class bitmart extends Exchange {
return;
}
//
- // {"message":"Maximum price is 0.112695"}
- // {"message":"Required Integer parameter 'status' is not present"}
- // {"message":"Required String parameter 'symbol' is not present"}
- // {"message":"Required Integer parameter 'offset' is not present"}
- // {"message":"Required Integer parameter 'limit' is not present"}
- // {"message":"Required Long parameter 'from' is not present"}
- // {"message":"Required Long parameter 'to' is not present"}
- // {"message":"Invalid status. status=6 not support any more, please use 3:deal_success orders, 4:cancelled orders"}
- // {"message":"Not found"}
- // {"message":"Place order error"}
+ // spot
//
- const feedback = this.id + ' ' + body;
- const message = this.safeString2 (response, 'message', 'msg');
- if (message !== undefined) {
+ // {"message":"Bad Request [to is empty]","code":50000,"trace":"f9d46e1b-4edb-4d07-a06e-4895fb2fc8fc","data":{}}
+ // {"message":"Bad Request [from is empty]","code":50000,"trace":"579986f7-c93a-4559-926b-06ba9fa79d76","data":{}}
+ // {"message":"Kline size over 500","code":50004,"trace":"d625caa8-e8ca-4bd2-b77c-958776965819","data":{}}
+ // {"message":"Balance not enough","code":50020,"trace":"7c709d6a-3292-462c-98c5-32362540aeef","data":{}}
+ //
+ // contract
+ //
+ // {"errno":"OK","message":"INVALID_PARAMETER","code":49998,"trace":"eb5ebb54-23cd-4de2-9064-e090b6c3b2e3","data":null}
+ //
+ const message = this.safeString (response, 'message');
+ const errorCode = this.safeString (response, 'code');
+ if (((errorCode !== undefined) && (errorCode !== '1000')) || ((message !== undefined) && (message !== 'OK'))) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], errorCode, feedback);
this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
throw new ExchangeError (feedback); // unknown message
@@ -18827,14 +22944,14 @@ module.exports = class bitmart extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],38:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],37:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ArgumentsRequired, AuthenticationError, ExchangeError, InsufficientFunds, InvalidOrder, BadSymbol } = require ('./base/errors');
-const { ROUND } = require ('./base/functions/number');
+const { ArgumentsRequired, AuthenticationError, ExchangeError, InsufficientFunds, InvalidOrder, BadSymbol, PermissionDenied, BadRequest } = require ('./base/errors');
+const { ROUND, TICK_SIZE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -18845,27 +22962,32 @@ module.exports = class bitmax extends Exchange {
'name': 'BitMax',
'countries': [ 'CN' ], // China
'rateLimit': 500,
- 'certified': false,
// new metainfo interface
'has': {
'CORS': false,
- 'fetchAccounts': true,
+ 'fetchMarkets': true,
+ 'fetchCurrencies': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
'fetchOHLCV': true,
- 'fetchMyTrades': false,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
- 'fetchOrderTrades': true,
- 'fetchClosedOrders': true,
- 'fetchTransactions': false,
- 'fetchCurrencies': true,
+ 'fetchTrades': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
+ 'createOrder': true,
+ 'cancelOrder': true,
'cancelAllOrders': true,
'fetchDepositAddress': true,
+ 'fetchTransactions': true,
+ 'fetchDeposits': true,
+ 'fetchWithdrawals': true,
+ 'fetchOrder': true,
+ 'fetchOrders': true,
+ 'fetchOpenOrders': true,
+ 'fetchClosedOrders': true,
},
'timeframes': {
'1m': '1',
- '3m': '3',
'5m': '5',
'15m': '15',
'30m': '30',
@@ -18885,7 +23007,7 @@ module.exports = class bitmax extends Exchange {
'test': 'https://bitmax-test.io',
'www': 'https://bitmax.io',
'doc': [
- 'https://github.com/bitmax-exchange/api-doc/blob/master/bitmax-api-doc-v1.2.md',
+ 'https://bitmax-exchange.github.io/bitmax-pro-api/#bitmax-pro-api-documentation',
],
'fees': 'https://bitmax.io/#/feeRate/tradeRate',
'referral': 'https://bitmax.io/#/register?inviteCode=EL6BXBQM',
@@ -18894,67 +23016,145 @@ module.exports = class bitmax extends Exchange {
'public': {
'get': [
'assets',
- 'depth',
- 'fees',
- 'quote',
+ 'products',
+ 'ticker',
+ 'barhist/info',
+ 'barhist',
'depth',
'trades',
- 'products',
- 'ticker/24hr',
- 'barhist',
- 'barhist/info',
- 'margin/ref-price',
+ 'cash/assets', // not documented
+ 'cash/products', // not documented
+ 'margin/assets', // not documented
+ 'margin/products', // not documented
+ 'futures/collateral',
+ 'futures/contracts',
+ 'futures/ref-px',
+ 'futures/market-data',
+ 'futures/funding-rates',
],
},
- 'private': {
+ 'accountCategory': {
'get': [
- 'deposit',
- 'user/info',
'balance',
- 'order/batch',
'order/open',
- 'order',
- 'order/history',
- 'order/{coid}',
- 'order/fills/{coid}',
- 'transaction',
- 'margin/balance',
- 'margin/order/open',
- 'margin/order',
+ 'order/status',
+ 'order/hist/current',
+ 'risk',
],
'post': [
- 'margin/order',
'order',
'order/batch',
],
'delete': [
- 'margin/order',
'order',
'order/all',
'order/batch',
],
},
+ 'accountGroup': {
+ 'get': [
+ 'cash/balance',
+ 'margin/balance',
+ 'margin/risk',
+ 'transfer',
+ 'futures/collateral-balance',
+ 'futures/position',
+ 'futures/risk',
+ 'futures/funding-payments',
+ 'order/hist',
+ ],
+ 'post': [
+ 'futures/transfer/deposit',
+ 'futures/transfer/withdraw',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'info',
+ 'wallet/transactions',
+ 'wallet/deposit/address', // not documented
+ ],
+ },
},
'fees': {
'trading': {
- 'tierBased': false,
+ 'tierBased': true,
'percentage': true,
'taker': 0.001,
'maker': 0.001,
},
},
+ 'precisionMode': TICK_SIZE,
'options': {
- 'accountGroup': undefined,
- 'parseOrderToPrecision': false,
+ 'account-category': 'cash', // 'cash'/'margin'/'futures'
+ 'account-group': undefined,
+ 'fetchClosedOrders': {
+ 'method': 'accountGroupGetOrderHist', // 'accountGroupGetAccountCategoryOrderHistCurrent'
+ },
},
'exceptions': {
'exact': {
+ // not documented
+ '1900': BadRequest, // {"code":1900,"message":"Invalid Http Request Input"}
'2100': AuthenticationError, // {"code":2100,"message":"ApiKeyFailure"}
'5002': BadSymbol, // {"code":5002,"message":"Invalid Symbol"}
'6001': BadSymbol, // {"code":6001,"message":"Trading is disabled on symbol."}
'6010': InsufficientFunds, // {'code': 6010, 'message': 'Not enough balance.'}
'60060': InvalidOrder, // { 'code': 60060, 'message': 'The order is already filled or canceled.' }
'600503': InvalidOrder, // {"code":600503,"message":"Notional is too small."}
+ // documented
+ '100001': BadRequest, // INVALID_HTTP_INPUT Http request is invalid
+ '100002': BadRequest, // DATA_NOT_AVAILABLE Some required data is missing
+ '100003': BadRequest, // KEY_CONFLICT The same key exists already
+ '100004': BadRequest, // INVALID_REQUEST_DATA The HTTP request contains invalid field or argument
+ '100005': BadRequest, // INVALID_WS_REQUEST_DATA Websocket request contains invalid field or argument
+ '100006': BadRequest, // INVALID_ARGUMENT The arugment is invalid
+ '100007': BadRequest, // ENCRYPTION_ERROR Something wrong with data encryption
+ '100008': BadSymbol, // SYMBOL_ERROR Symbol does not exist or not valid for the request
+ '100009': AuthenticationError, // AUTHORIZATION_NEEDED Authorization is require for the API access or request
+ '100010': BadRequest, // INVALID_OPERATION The action is invalid or not allowed for the account
+ '100011': BadRequest, // INVALID_TIMESTAMP Not a valid timestamp
+ '100012': BadRequest, // INVALID_STR_FORMAT String format does not
+ '100013': BadRequest, // INVALID_NUM_FORMAT Invalid number input
+ '100101': ExchangeError, // UNKNOWN_ERROR Some unknown error
+ '150001': BadRequest, // INVALID_JSON_FORMAT Require a valid json object
+ '200001': AuthenticationError, // AUTHENTICATION_FAILED Authorization failed
+ '200002': ExchangeError, // TOO_MANY_ATTEMPTS Tried and failed too many times
+ '200003': ExchangeError, // ACCOUNT_NOT_FOUND Account not exist
+ '200004': ExchangeError, // ACCOUNT_NOT_SETUP Account not setup properly
+ '200005': ExchangeError, // ACCOUNT_ALREADY_EXIST Account already exist
+ '200006': ExchangeError, // ACCOUNT_ERROR Some error related with error
+ '200007': ExchangeError, // CODE_NOT_FOUND
+ '200008': ExchangeError, // CODE_EXPIRED Code expired
+ '200009': ExchangeError, // CODE_MISMATCH Code does not match
+ '200010': AuthenticationError, // PASSWORD_ERROR Wrong assword
+ '200011': ExchangeError, // CODE_GEN_FAILED Do not generate required code promptly
+ '200012': ExchangeError, // FAKE_COKE_VERIFY
+ '200013': ExchangeError, // SECURITY_ALERT Provide security alert message
+ '200014': PermissionDenied, // RESTRICTED_ACCOUNT Account is restricted for certain activity, such as trading, or withdraw.
+ '200015': PermissionDenied, // PERMISSION_DENIED No enough permission for the operation
+ '300001': InvalidOrder, // INVALID_PRICE Order price is invalid
+ '300002': InvalidOrder, // INVALID_QTY Order size is invalid
+ '300003': InvalidOrder, // INVALID_SIDE Order side is invalid
+ '300004': InvalidOrder, // INVALID_NOTIONAL Notional is too small or too large
+ '300005': InvalidOrder, // INVALID_TYPE Order typs is invalid
+ '300006': InvalidOrder, // INVALID_ORDER_ID Order id is invalid
+ '300007': InvalidOrder, // INVALID_TIME_IN_FORCE Time In Force in order request is invalid
+ '300008': InvalidOrder, // INVALID_ORDER_PARAMETER Some order parameter is invalid
+ '300009': InvalidOrder, // TRADING_VIOLATION Trading violation on account or asset
+ '300011': InsufficientFunds, // INVALID_BALANCE No enough account or asset balance for the trading
+ '300012': BadSymbol, // INVALID_PRODUCT Not a valid product supported by exchange
+ '300013': InvalidOrder, // INVALID_BATCH_ORDER Some or all orders are invalid in batch order request
+ '300020': InvalidOrder, // TRADING_RESTRICTED There is some trading restriction on account or asset
+ '300021': InvalidOrder, // TRADING_DISABLED Trading is disabled on account or asset
+ '300031': InvalidOrder, // NO_MARKET_PRICE No market price for market type order trading
+ '310001': InsufficientFunds, // INVALID_MARGIN_BALANCE No enough margin balance
+ '310002': InvalidOrder, // INVALID_MARGIN_ACCOUNT Not a valid account for margin trading
+ '310003': InvalidOrder, // MARGIN_TOO_RISKY Leverage is too high
+ '310004': BadSymbol, // INVALID_MARGIN_ASSET This asset does not support margin trading
+ '310005': InvalidOrder, // INVALID_REFERENCE_PRICE There is no valid reference price
+ '510001': ExchangeError, // SERVER_ERROR Something wrong with server.
+ '900001': ExchangeError, // HUMAN_CHALLENGE Human change do not pass
},
'broad': {},
},
@@ -18965,38 +23165,92 @@ module.exports = class bitmax extends Exchange {
});
}
+ getAccount (params = {}) {
+ // get current or provided bitmax sub-account
+ const account = this.safeValue (params, 'account', this.options['account']);
+ return account.toLowerCase ().capitalize ();
+ }
+
async fetchCurrencies (params = {}) {
- const response = await this.publicGetAssets (params);
+ const assets = await this.publicGetAssets (params);
//
- // [
- // {
- // "assetCode" : "LTO",
- // "assetName" : "LTO",
- // "precisionScale" : 9,
- // "nativeScale" : 3,
- // "withdrawalFee" : 5.0,
- // "minWithdrawalAmt" : 10.0,
- // "status" : "Normal"
- // },
- // ]
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "assetCode" : "LTCBULL",
+ // "assetName" : "3X Long LTC Token",
+ // "precisionScale" : 9,
+ // "nativeScale" : 4,
+ // "withdrawalFee" : "0.2",
+ // "minWithdrawalAmt" : "1.0",
+ // "status" : "Normal"
+ // },
+ // ]
+ // }
//
+ const margin = await this.publicGetMarginAssets (params);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "assetCode":"BTT",
+ // "borrowAssetCode":"BTT-B",
+ // "interestAssetCode":"BTT-I",
+ // "nativeScale":0,
+ // "numConfirmations":1,
+ // "withdrawFee":"100.0",
+ // "minWithdrawalAmt":"1000.0",
+ // "statusCode":"Normal",
+ // "statusMessage":"",
+ // "interestRate":"0.001"
+ // }
+ // ]
+ // }
+ //
+ const cash = await this.publicGetCashAssets (params);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "assetCode":"LTCBULL",
+ // "nativeScale":4,
+ // "numConfirmations":20,
+ // "withdrawFee":"0.2",
+ // "minWithdrawalAmt":"1.0",
+ // "statusCode":"Normal",
+ // "statusMessage":""
+ // }
+ // ]
+ // }
+ //
+ const assetsData = this.safeValue (assets, 'data', []);
+ const marginData = this.safeValue (margin, 'data', []);
+ const cashData = this.safeValue (cash, 'data', []);
+ const assetsById = this.indexBy (assetsData, 'assetCode');
+ const marginById = this.indexBy (marginData, 'assetCode');
+ const cashById = this.indexBy (cashData, 'assetCode');
+ const dataById = this.deepExtend (assetsById, marginById, cashById);
+ const ids = Object.keys (dataById);
const result = {};
- for (let i = 0; i < response.length; i++) {
- const currency = response[i];
- const id = this.safeString (currency, 'assetCode');
- // todo: will need to rethink the fees
- // to add support for multiple withdrawal/deposit methods and
- // differentiated fees for each particular method
+ for (let i = 0; i < ids.length; i++) {
+ const id = ids[i];
+ const currency = dataById[id];
const code = this.safeCurrencyCode (id);
- const precision = this.safeInteger (currency, 'precisionScale');
- const fee = this.safeFloat (currency, 'withdrawalFee'); // todo: redesign
- const status = this.safeString (currency, 'status');
+ const precision = this.safeInteger2 (currency, 'precisionScale', 'nativeScale');
+ // why would the exchange API have different names for the same field
+ const fee = this.safeFloat2 (currency, 'withdrawFee', 'withdrawalFee');
+ const status = this.safeString2 (currency, 'status', 'statusCode');
const active = (status === 'Normal');
+ const margin = ('borrowAssetCode' in currency);
result[code] = {
'id': id,
'code': code,
'info': currency,
'type': undefined,
+ 'margin': margin,
'name': this.safeString (currency, 'assetName'),
'active': active,
'fee': fee,
@@ -19025,44 +23279,109 @@ module.exports = class bitmax extends Exchange {
}
async fetchMarkets (params = {}) {
- const response = await this.publicGetProducts (params);
+ const products = await this.publicGetProducts (params);
//
- // [
- // {
- // "symbol" : "BCH/USDT",
- // "domain" : "USDS",
- // "baseAsset" : "BCH",
- // "quoteAsset" : "USDT",
- // "priceScale" : 2,
- // "qtyScale" : 3,
- // "notionalScale" : 9,
- // "minQty" : "0.000000001",
- // "maxQty" : "1000000000",
- // "minNotional" : "5",
- // "maxNotional" : "200000",
- // "status" : "Normal",
- // "miningStatus" : "",
- // "marginTradable" : true,
- // "commissionType" : "Quote",
- // "commissionReserveRate" : 0.0010000000
- // },
- // ]
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "symbol":"LBA/BTC",
+ // "baseAsset":"LBA",
+ // "quoteAsset":"BTC",
+ // "status":"Normal",
+ // "minNotional":"0.000625",
+ // "maxNotional":"6.25",
+ // "marginTradable":false,
+ // "commissionType":"Quote",
+ // "commissionReserveRate":"0.001",
+ // "tickSize":"0.000000001",
+ // "lotSize":"1"
+ // },
+ // ]
+ // }
//
+ const cash = await this.publicGetCashProducts (params);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "symbol":"QTUM/BTC",
+ // "domain":"BTC",
+ // "tradingStartTime":1569506400000,
+ // "collapseDecimals":"0.0001,0.000001,0.00000001",
+ // "minQty":"0.000000001",
+ // "maxQty":"1000000000",
+ // "minNotional":"0.000625",
+ // "maxNotional":"12.5",
+ // "statusCode":"Normal",
+ // "statusMessage":"",
+ // "tickSize":"0.00000001",
+ // "useTick":false,
+ // "lotSize":"0.1",
+ // "useLot":false,
+ // "commissionType":"Quote",
+ // "commissionReserveRate":"0.001",
+ // "qtyScale":1,
+ // "priceScale":8,
+ // "notionalScale":4
+ // }
+ // ]
+ // }
+ //
+ const futures = await this.publicGetFuturesContracts (params);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "symbol":"BTC-PERP",
+ // "tradingStartTime":1579701600000,
+ // "collapseDecimals":"1,0.1,0.01",
+ // "minQty":"0.000000001",
+ // "maxQty":"1000000000",
+ // "minNotional":"5",
+ // "maxNotional":"1000000",
+ // "statusCode":"Normal",
+ // "statusMessage":"",
+ // "tickSize":"0.25",
+ // "lotSize":"0.0001",
+ // "priceScale":2,
+ // "qtyScale":4,
+ // "notionalScale":2
+ // }
+ // ]
+ // }
+ //
+ const productsData = this.safeValue (products, 'data', []);
+ const productsById = this.indexBy (productsData, 'symbol');
+ const cashData = this.safeValue (cash, 'data', []);
+ const futuresData = this.safeValue (futures, 'data', []);
+ const cashAndFuturesData = this.arrayConcat (cashData, futuresData);
+ const cashAndFuturesById = this.indexBy (cashAndFuturesData, 'symbol');
+ const dataById = this.deepExtend (productsById, cashAndFuturesById);
+ const ids = Object.keys (dataById);
const result = [];
- for (let i = 0; i < response.length; i++) {
- const market = response[i];
- const id = this.safeString (market, 'symbol');
+ for (let i = 0; i < ids.length; i++) {
+ const id = ids[i];
+ const market = dataById[id];
const baseId = this.safeString (market, 'baseAsset');
const quoteId = this.safeString (market, 'quoteAsset');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
- const symbol = base + '/' + quote;
const precision = {
- 'amount': this.safeInteger (market, 'qtyScale'),
- 'price': this.safeInteger (market, 'notionalScale'),
+ 'amount': this.safeFloat (market, 'lotSize'),
+ 'price': this.safeFloat (market, 'tickSize'),
};
const status = this.safeString (market, 'status');
const active = (status === 'Normal');
+ const type = ('useLot' in market) ? 'spot' : 'future';
+ const spot = (type === 'spot');
+ const future = (type === 'future');
+ let symbol = id;
+ if (!future) {
+ symbol = base + '/' + quote;
+ }
result.push ({
'id': id,
'symbol': symbol,
@@ -19071,6 +23390,9 @@ module.exports = class bitmax extends Exchange {
'baseId': baseId,
'quoteId': quoteId,
'info': market,
+ 'type': type,
+ 'spot': spot,
+ 'future': future,
'active': active,
'precision': precision,
'limits': {
@@ -19078,7 +23400,10 @@ module.exports = class bitmax extends Exchange {
'min': this.safeFloat (market, 'minQty'),
'max': this.safeFloat (market, 'maxQty'),
},
- 'price': { 'min': undefined, 'max': undefined },
+ 'price': {
+ 'min': this.safeFloat (market, 'tickSize'),
+ 'max': undefined,
+ },
'cost': {
'min': this.safeFloat (market, 'minNotional'),
'max': this.safeFloat (market, 'maxNotional'),
@@ -19090,6 +23415,7 @@ module.exports = class bitmax extends Exchange {
}
calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) {
+ // TODO: fee calculation here is incorrect, we need to support tiered fee calculation.
const market = this.markets[symbol];
let key = 'quote';
const rate = market[takerOrMaker];
@@ -19111,16 +23437,29 @@ module.exports = class bitmax extends Exchange {
}
async fetchAccounts (params = {}) {
- let accountGroup = this.safeString (this.options, 'accountGroup');
+ let accountGroup = this.safeString (this.options, 'account-group');
let response = undefined;
if (accountGroup === undefined) {
- response = await this.privateGetUserInfo (params);
+ response = await this.privateGetInfo (params);
//
// {
- // "accountGroup": 5
+ // "code":0,
+ // "data":{
+ // "email":"igor.kroitor@gmail.com",
+ // "accountGroup":8,
+ // "viewPermission":true,
+ // "tradePermission":true,
+ // "transferPermission":true,
+ // "cashAccount":["cshrHKLZCjlZ2ejqkmvIHHtPmLYqdnda"],
+ // "marginAccount":["martXoh1v1N3EMQC5FDtSj5VHso8aI2Z"],
+ // "futuresAccount":["futc9r7UmFJAyBY2rE3beA2JFxav2XFF"],
+ // "userUID":"U6491137460"
+ // }
// }
//
- accountGroup = this.safeString (response, 'accountGroup');
+ const data = this.safeValue (response, 'data', {});
+ accountGroup = this.safeString (data, 'accountGroup');
+ this.options['account-group'] = accountGroup;
}
return [
{
@@ -19135,33 +23474,74 @@ module.exports = class bitmax extends Exchange {
async fetchBalance (params = {}) {
await this.loadMarkets ();
await this.loadAccounts ();
- const response = await this.privateGetBalance (params);
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'fetchBalance', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeString (account, 'id');
+ const request = {
+ 'account-group': accountGroup,
+ };
+ let method = 'accountCategoryGetBalance';
+ if (accountCategory === 'futures') {
+ method = 'accountGroupGetFuturesCollateralBalance';
+ } else {
+ request['account-category'] = accountCategory;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // cash
//
// {
- // "code": 0,
- // "status": "success", // this field will be deprecated soon
- // "email": "foo@bar.com", // this field will be deprecated soon
- // "data": [
+ // 'code': 0,
+ // 'data': [
// {
- // "assetCode": "TSC",
- // "assetName": "Ethereum",
- // "totalAmount": "20.03", // total balance amount
- // "availableAmount": "20.03", // balance amount available to trade
- // "inOrderAmount": "0.000", // in order amount
- // "btcValue": "70.81" // the current BTC value of the balance, may be missing
+ // 'asset': 'BCHSV',
+ // 'totalBalance': '64.298000048',
+ // 'availableBalance': '64.298000048',
// },
// ]
// }
//
+ // margin
+ //
+ // {
+ // 'code': 0,
+ // 'data': [
+ // {
+ // 'asset': 'BCHSV',
+ // 'totalBalance': '64.298000048',
+ // 'availableBalance': '64.298000048',
+ // 'borrowed': '0',
+ // 'interest': '0',
+ // },
+ // ]
+ // }
+ //
+ // futures
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {"asset":"BTC","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"9456.59"},
+ // {"asset":"ETH","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"235.95"},
+ // {"asset":"USDT","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"1"},
+ // {"asset":"USDC","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"1.00035"},
+ // {"asset":"PAX","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"1.00045"},
+ // {"asset":"USDTR","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"1"}
+ // ]
+ // }
+ //
const result = { 'info': response };
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, 'assetCode'));
+ const code = this.safeCurrencyCode (this.safeString (balance, 'asset'));
const account = this.account ();
- account['free'] = this.safeFloat (balance, 'availableAmount');
- account['used'] = this.safeFloat (balance, 'inOrderAmount');
- account['total'] = this.safeFloat (balance, 'totalAmount');
+ account['free'] = this.safeFloat (balance, 'availableBalance');
+ account['total'] = this.safeFloat (balance, 'totalBalance');
result[code] = account;
}
return this.parseBalance (result);
@@ -19173,78 +23553,101 @@ module.exports = class bitmax extends Exchange {
const request = {
'symbol': market['id'],
};
- if (limit !== undefined) {
- request['n'] = limit; // default = maximum = 100
- }
const response = await this.publicGetDepth (this.extend (request, params));
//
// {
- // "m":"depth",
- // "ts":1570866464777,
- // "seqnum":5124140078,
- // "s":"ETH/USDT",
- // "asks":[
- // ["183.57","5.92"],
- // ["183.6","10.185"]
- // ],
- // "bids":[
- // ["183.54","0.16"],
- // ["183.53","10.8"],
- // ]
+ // "code":0,
+ // "data":{
+ // "m":"depth-snapshot",
+ // "symbol":"BTC-PERP",
+ // "data":{
+ // "ts":1590223998202,
+ // "seqnum":115444921,
+ // "asks":[
+ // ["9207.5","18.2383"],
+ // ["9207.75","18.8235"],
+ // ["9208","10.7873"],
+ // ],
+ // "bids":[
+ // ["9207.25","0.4009"],
+ // ["9207","0.003"],
+ // ["9206.5","0.003"],
+ // ]
+ // }
+ // }
// }
//
- const timestamp = this.safeInteger (response, 'ts');
- const result = this.parseOrderBook (response, timestamp);
- result['nonce'] = this.safeInteger (response, 'seqnum');
+ const data = this.safeValue (response, 'data', {});
+ const orderbook = this.safeValue (data, 'data', {});
+ const timestamp = this.safeInteger (orderbook, 'ts');
+ const result = this.parseOrderBook (orderbook, timestamp);
+ result['nonce'] = this.safeInteger (orderbook, 'seqnum');
return result;
}
parseTicker (ticker, market = undefined) {
//
// {
- // "symbol":"BCH/USDT",
- // "interval":"1d",
- // "barStartTime":1570866600000,
- // "openPrice":"225.16",
- // "closePrice":"224.05",
- // "highPrice":"226.08",
- // "lowPrice":"218.92",
- // "volume":"8607.036"
+ // "symbol":"QTUM/BTC",
+ // "open":"0.00016537",
+ // "close":"0.00019077",
+ // "high":"0.000192",
+ // "low":"0.00016537",
+ // "volume":"846.6",
+ // "ask":["0.00018698","26.2"],
+ // "bid":["0.00018408","503.7"],
+ // "type":"spot"
// }
//
- const timestamp = this.safeInteger (ticker, 'barStartTime');
- let symbol = undefined;
+ const timestamp = undefined;
const marketId = this.safeString (ticker, 'symbol');
+ let symbol = undefined;
if (marketId in this.markets_by_id) {
market = this.markets_by_id[marketId];
} else if (marketId !== undefined) {
- const [ baseId, quoteId ] = marketId.split ('/');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
+ const type = this.safeString (ticker, 'type');
+ if (type === 'spot') {
+ const [ baseId, quoteId ] = marketId.split ('/');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
}
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
- const last = this.safeFloat (ticker, 'closePrice');
+ const close = this.safeFloat (ticker, 'close');
+ const bid = this.safeValue (ticker, 'bid', []);
+ const ask = this.safeValue (ticker, 'ask', []);
+ const open = this.safeFloat (ticker, 'open');
+ let change = undefined;
+ let percentage = undefined;
+ let average = undefined;
+ if ((open !== undefined) && (close !== undefined)) {
+ change = close - open;
+ if (open > 0) {
+ percentage = change / open * 100;
+ }
+ average = this.sum (open, close) / 2;
+ }
return {
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'high': this.safeFloat (ticker, 'highPrice'),
- 'low': this.safeFloat (ticker, 'lowPrice'),
- 'bid': undefined,
- 'bidVolume': undefined,
- 'ask': undefined,
- 'askVolume': undefined,
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': this.safeFloat (bid, 0),
+ 'bidVolume': this.safeFloat (bid, 1),
+ 'ask': this.safeFloat (ask, 0),
+ 'askVolume': this.safeFloat (ask, 1),
'vwap': undefined,
- 'open': this.safeFloat (ticker, 'openPrice'),
- 'close': last,
- 'last': last,
+ 'open': open,
+ 'close': close,
+ 'last': close,
'previousClose': undefined, // previous day close
- 'change': undefined,
- 'percentage': undefined,
- 'average': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
'baseVolume': this.safeFloat (ticker, 'volume'),
'quoteVolume': undefined,
'info': ticker,
@@ -19265,39 +23668,81 @@ module.exports = class bitmax extends Exchange {
const request = {
'symbol': market['id'],
};
- const response = await this.publicGetTicker24hr (this.extend (request, params));
- return this.parseTicker (response, market);
+ const response = await this.publicGetTicker (this.extend (request, params));
+ //
+ // {
+ // "code":0,
+ // "data":{
+ // "symbol":"BTC-PERP", // or "BTC/USDT"
+ // "open":"9073",
+ // "close":"9185.75",
+ // "high":"9185.75",
+ // "low":"9185.75",
+ // "volume":"576.8334",
+ // "ask":["9185.75","15.5863"],
+ // "bid":["9185.5","0.003"],
+ // "type":"derivatives", // or "spot"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTicker (data, market);
}
async fetchTickers (symbols = undefined, params = {}) {
await this.loadMarkets ();
- const response = await this.publicGetTicker24hr (params);
- return this.parseTickers (response, symbols);
+ const request = {};
+ if (symbols !== undefined) {
+ const marketIds = this.marketIds (symbols);
+ request['symbol'] = marketIds.join (',');
+ }
+ const response = await this.publicGetTicker (this.extend (request, params));
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "symbol":"QTUM/BTC",
+ // "open":"0.00016537",
+ // "close":"0.00019077",
+ // "high":"0.000192",
+ // "low":"0.00016537",
+ // "volume":"846.6",
+ // "ask":["0.00018698","26.2"],
+ // "bid":["0.00018408","503.7"],
+ // "type":"spot"
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTickers (data, symbols);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// "m":"bar",
- // "s":"ETH/BTC",
- // "ba":"ETH",
- // "qa":"BTC",
- // "i":"1",
- // "t":1570867020000,
- // "o":"0.022023",
- // "c":"0.022018",
- // "h":"0.022023",
- // "l":"0.022018",
- // "v":"2.510",
+ // "s":"BTC/USDT",
+ // "data":{
+ // "i":"1",
+ // "ts":1590228000000,
+ // "o":"9139.59",
+ // "c":"9131.94",
+ // "h":"9139.99",
+ // "l":"9121.71",
+ // "v":"25.20648"
+ // }
// }
//
+ const data = this.safeValue (ohlcv, 'data', {});
return [
- this.safeInteger (ohlcv, 't'),
- this.safeFloat (ohlcv, 'o'),
- this.safeFloat (ohlcv, 'h'),
- this.safeFloat (ohlcv, 'l'),
- this.safeFloat (ohlcv, 'c'),
- this.safeFloat (ohlcv, 'v'),
+ this.safeInteger (data, 'ts'),
+ this.safeFloat (data, 'o'),
+ this.safeFloat (data, 'h'),
+ this.safeFloat (data, 'l'),
+ this.safeFloat (data, 'c'),
+ this.safeFloat (data, 'v'),
];
}
@@ -19311,17 +23756,42 @@ module.exports = class bitmax extends Exchange {
// if since and limit are not specified
// the exchange will return just 1 last candle by default
const duration = this.parseTimeframe (timeframe);
+ const options = this.safeValue (this.options, 'fetchOHLCV', {});
+ const defaultLimit = this.safeInteger (options, 'limit', 500);
if (since !== undefined) {
request['from'] = since;
- if (limit !== undefined) {
- request['to'] = this.sum (since, limit * duration * 1000, 1);
+ if (limit === undefined) {
+ limit = defaultLimit;
+ } else {
+ limit = Math.min (limit, defaultLimit);
}
+ request['to'] = this.sum (since, limit * duration * 1000, 1);
} else if (limit !== undefined) {
- request['to'] = this.milliseconds ();
- request['from'] = request['to'] - limit * duration * 1000 - 1;
+ request['n'] = limit; // max 500
}
const response = await this.publicGetBarhist (this.extend (request, params));
- return this.parseOHLCVs (response, market, timeframe, since, limit);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "m":"bar",
+ // "s":"BTC/USDT",
+ // "data":{
+ // "i":"1",
+ // "ts":1590228000000,
+ // "o":"9139.59",
+ // "c":"9131.94",
+ // "h":"9139.99",
+ // "l":"9121.71",
+ // "v":"25.20648"
+ // }
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
parseTrade (trade, market = undefined) {
@@ -19329,96 +23799,41 @@ module.exports = class bitmax extends Exchange {
// public fetchTrades
//
// {
- // "p": "13.75", // price
- // "q": "6.68", // quantity
- // "t": 1528988084944, // timestamp
- // "bm": False, // if true, the buyer is the market maker, we only use this field to "define the side" of a public trade
+ // "p":"9128.5", // price
+ // "q":"0.0030", // quantity
+ // "ts":1590229002385, // timestamp
+ // "bm":false, // if true, the buyer is the market maker, we only use this field to "define the side" of a public trade
+ // "seqnum":180143985289898554
// }
//
- // private fetchOrderTrades
- //
- // {
- // "ap": "0.029062965", // average filled price
- // "bb": "36851.981", // base asset total balance
- // "bc": "0", // if possitive, this is the BTMX commission charged by reverse mining, if negative, this is the mining output of the current fill.
- // "bpb": "36851.981", // base asset pending balance
- // "btmxBal": "0.0", // optional, the BTMX balance of the current account. This field is only available when bc is non-zero.
- // "cat": "CASH", // account category: CASH/MARGIN
- // "coid": "41g6wtPRFrJXgg6YxjqI6Qoog139Dmoi", // client order id, (needed to cancel order)
- // "ei": "NULL_VAL", // execution instruction
- // "errorCode": "NULL_VAL", // if the order is rejected, this field explains why
- // "execId": "12562285", // for each user, this is a strictly increasing long integer (represented as string)
- // "f": "78.074", // filled quantity, this is the aggregated quantity executed by all past fills
- // "fa": "BTC", // fee asset
- // "fee": "0.000693608", // fee
- // 'lp': "0.029064", // last price, the price executed by the last fill
- // "l": "11.932", // last quantity, the quantity executed by the last fill
- // "m": "order", // message type
- // "orderType": "Limit", // Limit, Market, StopLimit, StopMarket
- // "p": "0.029066", // limit price, only available for limit and stop limit orders
- // "q": "100.000", // order quantity
- // "qb": "98878.642957097", // quote asset total balance
- // "qpb": "98877.967247508", // quote asset pending balance
- // "s": "ETH/BTC", // symbol
- // "side": "Buy", // side
- // "status": "PartiallyFilled", // order status
- // "t": 1561131458389, // timestamp
- // }
- //
- const timestamp = this.safeInteger (trade, 't');
- const price = this.safeFloat (trade, 'p');
+ const timestamp = this.safeInteger (trade, 'ts');
+ const price = this.safeFloat2 (trade, 'price', 'p');
const amount = this.safeFloat (trade, 'q');
let cost = undefined;
if ((price !== undefined) && (amount !== undefined)) {
cost = price * amount;
}
- const buyerIsMaker = this.safeValue (trade, 'bm');
+ const buyerIsMaker = this.safeValue (trade, 'bm', false);
+ const makerOrTaker = buyerIsMaker ? 'maker' : 'taker';
+ const side = buyerIsMaker ? 'buy' : 'sell';
let symbol = undefined;
- const marketId = this.safeString (trade, 's');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = market.split ('/');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
- let fee = undefined;
- const feeCost = this.safeFloat (trade, 'fee');
- if (feeCost !== undefined) {
- const feeCurrencyId = this.safeString (trade, 'fa');
- const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
- fee = {
- 'cost': feeCost,
- 'currency': feeCurrencyCode,
- };
- }
- const orderId = this.safeString (trade, 'coid');
- let side = this.safeStringLower (trade, 'side');
- if ((side === undefined) && (buyerIsMaker !== undefined)) {
- side = buyerIsMaker ? 'buy' : 'sell';
- }
- const type = this.safeStringLower (trade, 'orderType');
return {
'info': trade,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'symbol': symbol,
'id': undefined,
- 'order': orderId,
- 'type': type,
- 'takerOrMaker': undefined,
+ 'order': undefined,
+ 'type': undefined,
+ 'takerOrMaker': makerOrTaker,
'side': side,
'price': price,
'amount': amount,
'cost': cost,
- 'fee': fee,
+ 'fee': undefined,
};
}
@@ -19429,24 +23844,25 @@ module.exports = class bitmax extends Exchange {
'symbol': market['id'],
};
if (limit !== undefined) {
- request['n'] = limit; // currently limited to 100 or fewer
+ request['n'] = limit; // max 100
}
const response = await this.publicGetTrades (this.extend (request, params));
//
// {
- // "m": "marketTrades", // message type
- // "s": "ETH/BTC", // symbol
- // "trades": [
- // {
- // "p": "13.75", // price
- // "q": "6.68", // quantity
- // "t": 1528988084944, // timestamp
- // "bm": False, // if true, the buyer is the market maker
- // },
- // ]
+ // "code":0,
+ // "data":{
+ // "m":"trades",
+ // "symbol":"BTC-PERP",
+ // "data":[
+ // {"p":"9128.5","q":"0.0030","ts":1590229002385,"bm":false,"seqnum":180143985289898554},
+ // {"p":"9129","q":"0.0030","ts":1590229002642,"bm":false,"seqnum":180143985289898587},
+ // {"p":"9129.5","q":"0.0030","ts":1590229021306,"bm":false,"seqnum":180143985289899043}
+ // ]
+ // }
// }
//
- const trades = this.safeValue (response, 'trades', []);
+ const records = this.safeValue (response, 'data', []);
+ const trades = this.safeValue (records, 'data', []);
return this.parseTrades (trades, market, since, limit);
}
@@ -19467,108 +23883,112 @@ module.exports = class bitmax extends Exchange {
// createOrder
//
// {
- // "coid": "xxx...xxx",
- // "action": "new",
- // "success": true // success = true means the order has been submitted to the matching engine.
+ // "id": "16e607e2b83a8bXHbAwwoqDo55c166fa",
+ // "orderId": "16e85b4d9b9a8bXHbAwwoqDoc3d66830",
+ // "orderType": "Market",
+ // "symbol": "BTC/USDT",
+ // "timestamp": 1573576916201
// }
//
// fetchOrder, fetchOpenOrders, fetchClosedOrders
//
// {
- // "accountCategory": "CASH",
- // "accountId": "cshKAhmTHQNUKhR1pQyrDOdotE3Tsnz4",
- // "avgPrice": "0.000000000",
- // "baseAsset": "ETH",
- // "btmxCommission": "0.000000000",
- // "coid": "41g6wtPRFrJXgg6Y7vpIkcCyWhgcK0cF", // the unique identifier, you will need, this value to cancel this order
- // "errorCode": "NULL_VAL",
- // "execId": "12452288",
- // "execInst": "NULL_VAL",
- // "fee": "0.000000000", // cumulative fee paid for this order
- // "feeAsset": "", // the asset
- // "filledQty": "0.000000000", // filled quantity
- // "notional": "0.000000000",
- // "orderPrice": "0.310000000", // only available for limit and stop limit orders
- // "orderQty": "1.000000000",
- // "orderType": "StopLimit",
- // "quoteAsset": "BTC",
- // "side": "Buy",
- // "status": "PendingNew",
- // "stopPrice": "0.300000000", // only available for stop market and stop limit orders
- // "symbol": "ETH/BTC",
- // "time": 1566091628227, // The last execution time of the order
- // "sendingTime": 1566091503547, // The sending time of the order
- // "userId": "supEQeSJQllKkxYSgLOoVk7hJAX59WSz"
+ // "symbol": "BTC/USDT",
+ // "price": "8131.22",
+ // "orderQty": "0.00082",
+ // "orderType": "Market",
+ // "avgPx": "7392.02",
+ // "cumFee": "0.005152238",
+ // "cumFilledQty": "0.00082",
+ // "errorCode": "",
+ // "feeAsset": "USDT",
+ // "lastExecTime": 1575953151764,
+ // "orderId": "a16eee20b6750866943712zWEDdAjt3",
+ // "seqNum": 2623469,
+ // "side": "Buy",
+ // "status": "Filled",
+ // "stopPrice": "",
+ // "execInst": "NULL_VAL"
// }
//
+ // {
+ // "ac": "FUTURES",
+ // "accountId": "testabcdefg",
+ // "avgPx": "0",
+ // "cumFee": "0",
+ // "cumQty": "0",
+ // "errorCode": "NULL_VAL",
+ // "execInst": "NULL_VAL",
+ // "feeAsset": "USDT",
+ // "lastExecTime": 1584072844085,
+ // "orderId": "r170d21956dd5450276356bbtcpKa74",
+ // "orderQty": "1.1499",
+ // "orderType": "Limit",
+ // "price": "4000",
+ // "sendingTime": 1584072841033,
+ // "seqNum": 24105338,
+ // "side": "Buy",
+ // "status": "Canceled",
+ // "stopPrice": "",
+ // "symbol": "BTC-PERP"
+ // },
+ //
const status = this.parseOrderStatus (this.safeString (order, 'status'));
const marketId = this.safeString (order, 'symbol');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('/');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
- const timestamp = this.safeInteger (order, 'sendingTime');
- let price = this.safeFloat (order, 'orderPrice');
+ const symbol = this.safeSymbol (marketId, market, '/');
+ let timestamp = this.safeInteger2 (order, 'timestamp', 'sendingTime');
+ let lastTradeTimestamp = this.safeInteger (order, 'lastExecTime');
+ const price = this.safeFloat (order, 'price');
const amount = this.safeFloat (order, 'orderQty');
- const filled = this.safeFloat (order, 'filledQty');
+ const average = this.safeFloat (order, 'avgPx');
+ const filled = this.safeFloat2 (order, 'cumFilledQty', 'cumQty');
let remaining = undefined;
- let cost = this.safeFloat (order, 'cummulativeQuoteQty');
if (filled !== undefined) {
+ if (filled === 0) {
+ timestamp = lastTradeTimestamp;
+ lastTradeTimestamp = undefined;
+ }
if (amount !== undefined) {
- remaining = amount - filled;
- if (this.options['parseOrderToPrecision']) {
- remaining = parseFloat (this.amountToPrecision (symbol, remaining));
- }
- remaining = Math.max (remaining, 0.0);
- }
- if (price !== undefined) {
- if (cost === undefined) {
- cost = price * filled;
- }
+ remaining = Math.max (0, amount - filled);
}
}
- const id = this.safeString (order, 'coid');
- let type = this.safeString (order, 'orderType');
- if (type !== undefined) {
- type = type.toLowerCase ();
- if (type === 'market') {
- if (price === 0.0) {
- if ((cost !== undefined) && (filled !== undefined)) {
- if ((cost > 0) && (filled > 0)) {
- price = cost / filled;
- }
- }
- }
+ let cost = undefined;
+ if ((average !== undefined) && (filled !== undefined)) {
+ cost = average * filled;
+ }
+ const id = this.safeString (order, 'orderId');
+ let clientOrderId = this.safeString (order, 'id');
+ if (clientOrderId !== undefined) {
+ if (clientOrderId.length < 1) {
+ clientOrderId = undefined;
}
}
+ const type = this.safeStringLower (order, 'orderType');
const side = this.safeStringLower (order, 'side');
- const fee = {
- 'cost': this.safeFloat (order, 'fee'),
- 'currency': this.safeString (order, 'feeAsset'),
- };
- const average = this.safeFloat (order, 'avgPrice');
- const clientOrderId = id;
+ const feeCost = this.safeFloat (order, 'cumFee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (order, 'feeAsset');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ const stopPrice = this.safeFloat (order, 'stopPrice');
return {
'info': order,
'id': id,
- 'clientOrderId': clientOrderId,
+ 'clientOrderId': undefined,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'lastTradeTimestamp': undefined,
+ 'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -19584,258 +24004,289 @@ module.exports = class bitmax extends Exchange {
await this.loadMarkets ();
await this.loadAccounts ();
const market = this.market (symbol);
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'createOrder', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'id');
const request = {
- 'coid': this.coid (), // a unique identifier of length 32
- // 'time': this.milliseconds (), // milliseconds since UNIX epoch in UTC, this is filled in the private section of the sign() method below
+ 'account-group': accountGroup,
+ 'account-category': accountCategory,
'symbol': market['id'],
- // 'orderPrice': this.priceToPrecision (symbol, price), // optional, limit price of the order. This field is required for limit orders and stop limit orders
- // 'stopPrice': '15.7', // optional, stopPrice of the order. This field is required for stop_market orders and stop limit orders
+ 'time': this.milliseconds (),
'orderQty': this.amountToPrecision (symbol, amount),
- 'orderType': type, // order type, you shall specify one of the following: "limit", "market", "stop_market", "stop_limit"
+ 'orderType': type, // "limit", "market", "stop_market", "stop_limit"
'side': side, // "buy" or "sell"
- // 'postOnly': true, // optional, if true, the order will either be posted to the limit order book or be cancelled, i.e. the order cannot take liquidity, default is false
- // 'timeInForce': 'GTC', // optional, supports "GTC" good-till-canceled and "IOC" immediate-or-cancel
+ // 'orderPrice': this.priceToPrecision (symbol, price),
+ // 'stopPrice': this.priceToPrecision (symbol, stopPrice), // required for stop orders
+ // 'postOnly': 'false', // 'false', 'true'
+ // 'timeInForce': 'GTC', // GTC, IOC, FOK
+ // 'respInst': 'ACK', // ACK, 'ACCEPT, DONE
};
+ if (clientOrderId !== undefined) {
+ request['id'] = clientOrderId;
+ params = this.omit (params, [ 'clientOrderId', 'id' ]);
+ }
if ((type === 'limit') || (type === 'stop_limit')) {
request['orderPrice'] = this.priceToPrecision (symbol, price);
}
- const response = await this.privatePostOrder (this.extend (request, params));
+ if ((type === 'stop_limit') || (type === 'stop_market')) {
+ const stopPrice = this.safeFloat (params, 'stopPrice');
+ if (stopPrice === undefined) {
+ throw new InvalidOrder (this.id + ' createOrder requires a stopPrice parameter for ' + type + ' orders');
+ } else {
+ request['stopPrice'] = this.priceToPrecision (symbol, stopPrice);
+ params = this.omit (params, 'stopPrice');
+ }
+ }
+ const response = await this.accountCategoryPostOrder (this.extend (request, params));
//
// {
// "code": 0,
- // "email": "foo@bar.com", // this field will be deprecated soon
- // "status": "success", // this field will be deprecated soon
// "data": {
- // "coid": "xxx...xxx",
- // "action": "new",
- // "success": true, // success = true means the order has been submitted to the matching engine
+ // "ac": "MARGIN",
+ // "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
+ // "action": "place-order",
+ // "info": {
+ // "id": "16e607e2b83a8bXHbAwwoqDo55c166fa",
+ // "orderId": "16e85b4d9b9a8bXHbAwwoqDoc3d66830",
+ // "orderType": "Market",
+ // "symbol": "BTC/USDT",
+ // "timestamp": 1573576916201
+ // },
+ // "status": "Ack"
// }
// }
//
const data = this.safeValue (response, 'data', {});
- return this.parseOrder (data, market);
+ const info = this.safeValue (data, 'info', {});
+ return this.parseOrder (info, market);
}
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
await this.loadAccounts ();
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- }
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'fetchOrder', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
const request = {
- 'coid': id,
+ 'account-group': accountGroup,
+ 'account-category': accountCategory,
+ 'orderId': id,
};
- const response = await this.privateGetOrderCoid (this.extend (request, params));
+ const response = await this.accountCategoryGetOrderStatus (this.extend (request, params));
//
// {
- // 'code': 0,
- // 'status': 'success', // this field will be deprecated soon
- // 'email': 'foo@bar.com', // this field will be deprecated soon
- // "data": {
- // "accountCategory": "CASH",
- // "accountId": "cshKAhmTHQNUKhR1pQyrDOdotE3Tsnz4",
- // "avgPrice": "0.000000000",
- // "baseAsset": "ETH",
- // "btmxCommission": "0.000000000",
- // "coid": "41g6wtPRFrJXgg6Y7vpIkcCyWhgcK0cF", // the unique identifier, you will need, this value to cancel this order
- // "errorCode": "NULL_VAL",
- // "execId": "12452288",
- // "execInst": "NULL_VAL",
- // "fee": "0.000000000", // cumulative fee paid for this order
- // "feeAsset": "", // the asset
- // "filledQty": "0.000000000", // filled quantity
- // "notional": "0.000000000",
- // "orderPrice": "0.310000000", // only available for limit and stop limit orders
- // "orderQty": "1.000000000",
- // "orderType": "StopLimit",
- // "quoteAsset": "BTC",
- // "side": "Buy",
- // "status": "PendingNew",
- // "stopPrice": "0.300000000", // only available for stop market and stop limit orders
- // "symbol": "ETH/BTC",
- // "time": 1566091628227, // The last execution time of the order
- // "sendingTime": 1566091503547, // The sending time of the order
- // "userId": "supEQeSJQllKkxYSgLOoVk7hJAX59WSz"
- // }
- // }
- //
- const data = this.safeValue (response, 'data', {});
- return this.parseOrder (data, market);
- }
-
- async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- await this.loadAccounts ();
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- }
- const request = {
- 'coid': id,
- };
- const response = await this.privateGetOrderFillsCoid (this.extend (request, params));
- //
- // {
- // 'code': 0,
- // 'status': 'success', // this field will be deprecated soon
- // 'email': 'foo@bar.com', // this field will be deprecated soon
+ // "code": 0,
+ // "accountCategory": "CASH",
+ // "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
// "data": [
// {
- // "ap": "0.029062965", // average filled price
- // "bb": "36851.981", // base asset total balance
- // "bc": "0", // if possitive, this is the BTMX commission charged by reverse mining, if negative, this is the mining output of the current fill.
- // "bpb": "36851.981", // base asset pending balance
- // "btmxBal": "0.0", // optional, the BTMX balance of the current account. This field is only available when bc is non-zero.
- // "cat": "CASH", // account category: CASH/MARGIN
- // "coid": "41g6wtPRFrJXgg6YxjqI6Qoog139Dmoi", // client order id, (needed to cancel order)
- // "ei": "NULL_VAL", // execution instruction
- // "errorCode": "NULL_VAL", // if the order is rejected, this field explains why
- // "execId": "12562285", // for each user, this is a strictly increasing long integer (represented as string)
- // "f": "78.074", // filled quantity, this is the aggregated quantity executed by all past fills
- // "fa": "BTC", // fee asset
- // "fee": "0.000693608", // fee
- // 'lp': "0.029064", // last price, the price executed by the last fill
- // "l": "11.932", // last quantity, the quantity executed by the last fill
- // "m": "order", // message type
- // "orderType": "Limit", // Limit, Market, StopLimit, StopMarket
- // "p": "0.029066", // limit price, only available for limit and stop limit orders
- // "q": "100.000", // order quantity
- // "qb": "98878.642957097", // quote asset total balance
- // "qpb": "98877.967247508", // quote asset pending balance
- // "s": "ETH/BTC", // symbol
- // "side": "Buy", // side
- // "status": "PartiallyFilled", // order status
- // "t": 1561131458389, // timestamp
- // },
+ // "symbol": "BTC/USDT",
+ // "price": "8131.22",
+ // "orderQty": "0.00082",
+ // "orderType": "Market",
+ // "avgPx": "7392.02",
+ // "cumFee": "0.005152238",
+ // "cumFilledQty": "0.00082",
+ // "errorCode": "",
+ // "feeAsset": "USDT",
+ // "lastExecTime": 1575953151764,
+ // "orderId": "a16eee20b6750866943712zWEDdAjt3",
+ // "seqNum": 2623469,
+ // "side": "Buy",
+ // "status": "Filled",
+ // "stopPrice": "",
+ // "execInst": "NULL_VAL"
+ // }
// ]
// }
//
const data = this.safeValue (response, 'data', {});
- return this.parseTrades (data, market, since, limit);
+ return this.parseOrder (data);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
await this.loadAccounts ();
let market = undefined;
- const request = {
- // 'side': 'buy', // or 'sell', optional
- };
if (symbol !== undefined) {
market = this.market (symbol);
- request['symbol'] = market['id'];
}
- const response = await this.privateGetOrderOpen (this.extend (request, params));
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'fetchOpenOrders', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
+ const request = {
+ 'account-group': accountGroup,
+ 'account-category': accountCategory,
+ };
+ const response = await this.accountCategoryGetOrderOpen (this.extend (request, params));
//
// {
- // 'code': 0,
- // 'status': 'success', // this field will be deprecated soon
- // 'email': 'foo@bar.com', // this field will be deprecated soon
+ // "ac": "CASH",
+ // "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
+ // "code": 0,
// "data": [
// {
- // "accountCategory": "CASH",
- // "accountId": "cshKAhmTHQNUKhR1pQyrDOdotE3Tsnz4",
- // "avgPrice": "0.000000000",
- // "baseAsset": "ETH",
- // "btmxCommission": "0.000000000",
- // "coid": "41g6wtPRFrJXgg6Y7vpIkcCyWhgcK0cF", // the unique identifier, you will need, this value to cancel this order
- // "errorCode": "NULL_VAL",
- // "execId": "12452288",
- // "execInst": "NULL_VAL",
- // "fee": "0.000000000", // cumulative fee paid for this order
- // "feeAsset": "", // the asset
- // "filledQty": "0.000000000", // filled quantity
- // "notional": "0.000000000",
- // "orderPrice": "0.310000000", // only available for limit and stop limit orders
- // "orderQty": "1.000000000",
- // "orderType": "StopLimit",
- // "quoteAsset": "BTC",
- // "side": "Buy",
- // "status": "PendingNew",
- // "stopPrice": "0.300000000", // only available for stop market and stop limit orders
- // "symbol": "ETH/BTC",
- // "time": 1566091628227, // The last execution time of the order
- // "sendingTime": 1566091503547, // The sending time of the order
- // "userId": "supEQeSJQllKkxYSgLOoVk7hJAX59WSz"
+ // "avgPx": "0", // Average filled price of the order
+ // "cumFee": "0", // cumulative fee paid for this order
+ // "cumFilledQty": "0", // cumulative filled quantity
+ // "errorCode": "", // error code; could be empty
+ // "feeAsset": "USDT", // fee asset
+ // "lastExecTime": 1576019723550, // The last execution time of the order
+ // "orderId": "s16ef21882ea0866943712034f36d83", // server provided orderId
+ // "orderQty": "0.0083", // order quantity
+ // "orderType": "Limit", // order type
+ // "price": "7105", // order price
+ // "seqNum": 8193258, // sequence number
+ // "side": "Buy", // order side
+ // "status": "New", // order status on matching engine
+ // "stopPrice": "", // only available for stop market and stop limit orders; otherwise empty
+ // "symbol": "BTC/USDT",
+ // "execInst": "NULL_VAL" // execution instruction
// },
// ]
// }
//
const data = this.safeValue (response, 'data', []);
- return this.parseOrders (data, market, since, limit);
+ if (accountCategory === 'futures') {
+ return this.parseOrders (data, market, since, limit);
+ }
+ // a workaround for https://github.com/ccxt/ccxt/issues/7187
+ const orders = [];
+ for (let i = 0; i < data.length; i++) {
+ const order = this.parseOrder (data[i], market);
+ orders.push (order);
+ }
+ return this.filterBySymbolSinceLimit (orders, symbol, since, limit);
}
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
await this.loadAccounts ();
let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ const defaultAccountCategory = this.safeString (this.options, 'account-category');
+ const options = this.safeValue (this.options, 'fetchClosedOrders', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
const request = {
- // 'symbol': 'ETH/BTC', // optional
- // 'category': 'CASH', // optional, string
- // 'orderType': 'Market', // optional, string
- // 'page': 1, // optional, integer type, starts at 1
- // 'pageSize': 100, // optional, integer type
+ 'account-group': accountGroup,
+ // 'category': accountCategory,
+ // 'symbol': market['id'],
+ // 'orderType': 'market', // optional, string
// 'side': 'buy', // or 'sell', optional, case insensitive.
- // 'startTime': 1566091628227, // optional, integer milliseconds since UNIX epoch representing the start of the range
- // 'endTime': 1566091628227, // optional, integer milliseconds since UNIX epoch representing the end of the range
- // 'status': 'Filled', // optional, can only be one of "Filled", "Canceled", "Rejected"
+ // 'status': 'Filled', // "Filled", "Canceled", or "Rejected"
+ // 'startTime': exchange.milliseconds (),
+ // 'endTime': exchange.milliseconds (),
+ // 'page': 1,
+ // 'pageSize': 100,
};
if (symbol !== undefined) {
market = this.market (symbol);
request['symbol'] = market['id'];
}
+ const method = this.safeValue (options, 'method', 'accountGroupGetOrderHist');
+ if (method === 'accountGroupGetOrderHist') {
+ if (accountCategory !== undefined) {
+ request['category'] = accountCategory;
+ }
+ } else {
+ request['account-category'] = accountCategory;
+ }
if (since !== undefined) {
request['startTime'] = since;
}
if (limit !== undefined) {
- request['n'] = limit; // default 15, max 50
+ request['pageSize'] = limit;
}
- const response = await this.privateGetOrderHistory (this.extend (request, params));
+ const response = await this[method] (this.extend (request, params));
+ //
+ // accountCategoryGetOrderHistCurrent
//
// {
- // 'code': 0,
- // 'status': 'success', // this field will be deprecated soon
- // 'email': 'foo@bar.com', // this field will be deprecated soon
- // 'data': {
- // 'page': 1,
- // 'pageSize': 20,
- // 'limit': 500,
- // 'hasNext': False,
- // 'data': [
+ // "code":0,
+ // "accountId":"cshrHKLZCjlZ2ejqkmvIHHtPmLYqdnda",
+ // "ac":"CASH",
+ // "data":[
+ // {
+ // "seqNum":15561826728,
+ // "orderId":"a17294d305c0U6491137460bethu7kw9",
+ // "symbol":"ETH/USDT",
+ // "orderType":"Limit",
+ // "lastExecTime":1591635618200,
+ // "price":"200",
+ // "orderQty":"0.1",
+ // "side":"Buy",
+ // "status":"Canceled",
+ // "avgPx":"0",
+ // "cumFilledQty":"0",
+ // "stopPrice":"",
+ // "errorCode":"",
+ // "cumFee":"0",
+ // "feeAsset":"USDT",
+ // "execInst":"NULL_VAL"
+ // }
+ // ]
+ // }
+ //
+ // accountGroupGetOrderHist
+ //
+ // {
+ // "code": 0,
+ // "data": {
+ // "data": [
// {
- // 'time': 1566091429000, // The last execution time of the order (This timestamp is in second level resolution)
- // 'coid': 'QgQIMJhPFrYfUf60ZTihmseTqhzzwOCx',
- // 'execId': '331',
- // 'symbol': 'BTMX/USDT',
- // 'orderType': 'Market',
- // 'baseAsset': 'BTMX',
- // 'quoteAsset': 'USDT',
- // 'side': 'Buy',
- // 'stopPrice': '0.000000000', // only meaningful for stop market and stop limit orders
- // 'orderPrice': '0.123000000', // only meaningful for limit and stop limit orders
- // 'orderQty': '9229.409000000',
- // 'filledQty': '9229.409000000',
- // 'avgPrice': '0.095500000',
- // 'fee': '0.352563424',
- // 'feeAsset': 'USDT',
- // 'btmxCommission': '0.000000000',
- // 'status': 'Filled',
- // 'notional': '881.408559500',
- // 'userId': '5DNEppWy33SayHjFQpgQUTjwNMSjEhD3',
- // 'accountId': 'ACPHERRWRIA3VQADMEAB2ZTLYAXNM3PJ',
- // 'accountCategory': 'CASH',
- // 'errorCode': 'NULL_VAL',
- // 'execInst': 'NULL_VAL',
- // "sendingTime": 1566091382736, // The sending time of the order
- // },
- // ]
+ // "ac": "FUTURES",
+ // "accountId": "testabcdefg",
+ // "avgPx": "0",
+ // "cumFee": "0",
+ // "cumQty": "0",
+ // "errorCode": "NULL_VAL",
+ // "execInst": "NULL_VAL",
+ // "feeAsset": "USDT",
+ // "lastExecTime": 1584072844085,
+ // "orderId": "r170d21956dd5450276356bbtcpKa74",
+ // "orderQty": "1.1499",
+ // "orderType": "Limit",
+ // "price": "4000",
+ // "sendingTime": 1584072841033,
+ // "seqNum": 24105338,
+ // "side": "Buy",
+ // "status": "Canceled",
+ // "stopPrice": "",
+ // "symbol": "BTC-PERP"
+ // },
+ // ],
+ // "hasNext": False,
+ // "limit": 500,
+ // "page": 1,
+ // "pageSize": 20
// }
// }
//
- const data = this.safeValue (response, 'data', {});
- const orders = this.safeValue (data, 'data', []);
- return this.parseOrders (orders, market, since, limit);
+ let data = this.safeValue (response, 'data');
+ const isArray = Array.isArray (data);
+ if (!isArray) {
+ data = this.safeValue (data, 'data', []);
+ }
+ return this.parseOrders (data, market, since, limit);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -19845,149 +24296,351 @@ module.exports = class bitmax extends Exchange {
await this.loadMarkets ();
await this.loadAccounts ();
const market = this.market (symbol);
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'cancelOrder', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'id');
const request = {
+ 'account-group': accountGroup,
+ 'account-category': accountCategory,
'symbol': market['id'],
- 'coid': this.coid (),
- 'origCoid': id,
- // 'time': this.milliseconds (), // this is filled in the private section of the sign() method below
+ 'time': this.milliseconds (),
+ 'id': 'foobar',
};
- const response = await this.privateDeleteOrder (this.extend (request, params));
+ if (clientOrderId === undefined) {
+ request['orderId'] = id;
+ } else {
+ request['id'] = clientOrderId;
+ params = this.omit (params, [ 'clientOrderId', 'id' ]);
+ }
+ const response = await this.accountCategoryDeleteOrder (this.extend (request, params));
//
// {
- // 'code': 0,
- // 'status': 'success', // this field will be deprecated soon
- // 'email': 'foo@bar.com', // this field will be deprecated soon
- // 'data': {
- // 'action': 'cancel',
- // 'coid': 'gaSRTi3o3Yo4PaXpVK0NSLP47vmJuLea',
- // 'success': True,
+ // "code": 0,
+ // "data": {
+ // "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
+ // "ac": "CASH",
+ // "action": "cancel-order",
+ // "status": "Ack",
+ // "info": {
+ // "id": "wv8QGquoeamhssvQBeHOHGQCGlcBjj23",
+ // "orderId": "16e6198afb4s8bXHbAwwoqDo2ebc19dc",
+ // "orderType": "", // could be empty
+ // "symbol": "ETH/USDT",
+ // "timestamp": 1573594877822
+ // }
// }
// }
//
- const order = this.safeValue (response, 'data', {});
- return this.parseOrder (order);
+ const data = this.safeValue (response, 'data', {});
+ const info = this.safeValue (data, 'info', {});
+ return this.parseOrder (info, market);
}
async cancelAllOrders (symbol = undefined, params = {}) {
await this.loadMarkets ();
await this.loadAccounts ();
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'cancelAllOrders', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
const request = {
- // 'side': 'buy', // optional string field (case-insensitive), either "buy" or "sell"
+ 'account-group': accountGroup,
+ 'account-category': accountCategory,
+ 'time': this.milliseconds (),
};
let market = undefined;
if (symbol !== undefined) {
market = this.market (symbol);
- request['symbol'] = market['id']; // optional
+ request['symbol'] = market['id'];
}
- const response = await this.privateDeleteOrderAll (this.extend (request, params));
+ const response = await this.accountCategoryDeleteOrderAll (this.extend (request, params));
//
- // ?
+ // {
+ // "code": 0,
+ // "data": {
+ // "ac": "CASH",
+ // "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
+ // "action": "cancel-all",
+ // "info": {
+ // "id": "2bmYvi7lyTrneMzpcJcf2D7Pe9V1P9wy",
+ // "orderId": "",
+ // "orderType": "NULL_VAL",
+ // "symbol": "",
+ // "timestamp": 1574118495462
+ // },
+ // "status": "Ack"
+ // }
+ // }
//
return response;
}
- coid () {
- const uuid = this.uuid ();
- const parts = uuid.split ('-');
- const clientOrderId = parts.join ('');
- const coid = clientOrderId.slice (0, 32);
- return coid;
- }
-
- async fetchDepositAddress (code, params = {}) {
- await this.loadMarkets ();
- await this.loadAccounts ();
- const currency = this.currency (code);
- const request = {
- 'requestId': this.coid (),
- // 'time': this.milliseconds (), // this is filled in the private section of the sign() method below
- 'assetCode': currency['id'],
- };
- // note: it is highly recommended to use V2 version of this route,
- // especially for assets with multiple block chains such as USDT.
- const response = await this.privateGetDeposit (this.extend (request, params));
- //
- // v1
+ parseDepositAddress (depositAddress, currency = undefined) {
//
// {
- // "data": {
- // "address": "0x26a3CB49578F07000575405a57888681249c35Fd"
- // },
- // "email": "igor.kroitor@gmial.com",
- // "status": "success",
+ // address: "0xe7c70b4e73b6b450ee46c3b5c0f5fb127ca55722",
+ // destTag: "",
+ // tagType: "",
+ // tagId: "",
+ // chainName: "ERC20",
+ // numConfirmations: 20,
+ // withdrawalFee: 1,
+ // nativeScale: 4,
+ // tips: []
// }
//
- // v2
- //
- // {
- // "code": 0,
- // "data": [
- // {
- // "asset": "XRP",
- // "blockChain": "Ripple",
- // "addressData": {
- // "address": "rpinhtY4p35bPmVXPbfWRUtZ1w1K1gYShB",
- // "destTag": "54301"
- // }
- // }
- // ],
- // "email": "xxx@xxx.com",
- // "status": "success" // the request has been submitted to the server
- // }
- //
- let addressData = this.safeValue (response, 'data');
- if (Array.isArray (addressData)) {
- const firstElement = this.safeValue (addressData, 0, {});
- addressData = this.safeValue (firstElement, 'addressData', {});
- }
- const address = this.safeString (addressData, 'address');
- const tag = this.safeString (addressData, 'destTag');
+ const address = this.safeString (depositAddress, 'address');
+ const tagId = this.safeString (depositAddress, 'tagId');
+ const tag = this.safeString (depositAddress, tagId);
this.checkAddress (address);
+ const code = (currency === undefined) ? undefined : currency['code'];
return {
'currency': code,
'address': address,
'tag': tag,
+ 'info': depositAddress,
+ };
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const chainName = this.safeString (params, 'chainName');
+ params = this.omit (params, 'chainName');
+ const request = {
+ 'asset': currency['id'],
+ };
+ const response = await this.privateGetWalletDepositAddress (this.extend (request, params));
+ //
+ // {
+ // "code":0,
+ // "data":{
+ // "asset":"USDT",
+ // "assetName":"Tether",
+ // "address":[
+ // {
+ // "address":"1N22odLHXnLPCjC8kwBJPTayarr9RtPod6",
+ // "destTag":"",
+ // "tagType":"",
+ // "tagId":"",
+ // "chainName":"Omni",
+ // "numConfirmations":3,
+ // "withdrawalFee":4.7,
+ // "nativeScale":4,
+ // "tips":[]
+ // },
+ // {
+ // "address":"0xe7c70b4e73b6b450ee46c3b5c0f5fb127ca55722",
+ // "destTag":"",
+ // "tagType":"",
+ // "tagId":"",
+ // "chainName":"ERC20",
+ // "numConfirmations":20,
+ // "withdrawalFee":1.0,
+ // "nativeScale":4,
+ // "tips":[]
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const addresses = this.safeValue (data, 'address', []);
+ const numAddresses = addresses.length;
+ let address = undefined;
+ if (numAddresses > 1) {
+ const addressesByChainName = this.indexBy (addresses, 'chainName');
+ if (chainName === undefined) {
+ const chainNames = Object.keys (addressesByChainName);
+ const chains = chainNames.join (', ');
+ throw new ArgumentsRequired (this.id + ' fetchDepositAddress returned more than one address, a chainName parameter is required, one of ' + chains);
+ }
+ address = this.safeValue (addressesByChainName, chainName, {});
+ } else {
+ // first address
+ address = this.safeValue (addresses, 0, {});
+ }
+ const result = this.parseDepositAddress (address, currency);
+ return this.extend (result, {
'info': response,
+ });
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'txType': 'deposit',
+ };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'txType': 'withdrawal',
+ };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'asset': currency['id'],
+ // 'page': 1,
+ // 'pageSize': 20,
+ // 'startTs': this.milliseconds (),
+ // 'endTs': this.milliseconds (),
+ // 'txType': undefned, // deposit, withdrawal
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['asset'] = currency['id'];
+ }
+ if (since !== undefined) {
+ request['startTs'] = since;
+ }
+ if (limit !== undefined) {
+ request['pageSize'] = limit;
+ }
+ const response = await this.privateGetWalletTransactions (this.extend (request, params));
+ //
+ // {
+ // code: 0,
+ // data: {
+ // data: [
+ // {
+ // requestId: "wuzd1Ojsqtz4bCA3UXwtUnnJDmU8PiyB",
+ // time: 1591606166000,
+ // asset: "USDT",
+ // transactionType: "deposit",
+ // amount: "25",
+ // commission: "0",
+ // networkTransactionId: "0xbc4eabdce92f14dbcc01d799a5f8ca1f02f4a3a804b6350ea202be4d3c738fce",
+ // status: "pending",
+ // numConfirmed: 8,
+ // numConfirmations: 20,
+ // destAddress: { address: "0xe7c70b4e73b6b450ee46c3b5c0f5fb127ca55722" }
+ // }
+ // ],
+ // page: 1,
+ // pageSize: 20,
+ // hasNext: false
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const transactions = this.safeValue (data, 'data', []);
+ return this.parseTransactions (transactions, currency, since, limit);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'reviewing': 'pending',
+ 'pending': 'pending',
+ 'confirmed': 'ok',
+ 'rejected': 'rejected',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // {
+ // requestId: "wuzd1Ojsqtz4bCA3UXwtUnnJDmU8PiyB",
+ // time: 1591606166000,
+ // asset: "USDT",
+ // transactionType: "deposit",
+ // amount: "25",
+ // commission: "0",
+ // networkTransactionId: "0xbc4eabdce92f14dbcc01d799a5f8ca1f02f4a3a804b6350ea202be4d3c738fce",
+ // status: "pending",
+ // numConfirmed: 8,
+ // numConfirmations: 20,
+ // destAddress: {
+ // address: "0xe7c70b4e73b6b450ee46c3b5c0f5fb127ca55722",
+ // destTag: "..." // for currencies that have it
+ // }
+ // }
+ //
+ const id = this.safeString (transaction, 'requestId');
+ const amount = this.safeFloat (transaction, 'amount');
+ const destAddress = this.safeValue (transaction, 'destAddress', {});
+ const address = this.safeString (destAddress, 'address');
+ const tag = this.safeString (destAddress, 'destTag');
+ const txid = this.safeString (transaction, 'networkTransactionId');
+ const type = this.safeString (transaction, 'transactionType');
+ const timestamp = this.safeInteger (transaction, 'time');
+ const currencyId = this.safeString (transaction, 'asset');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const feeCost = this.safeFloat (transaction, 'commission');
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': code,
+ 'amount': amount,
+ 'address': address,
+ 'addressTo': address,
+ 'addressFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'tagFrom': undefined,
+ 'status': status,
+ 'type': type,
+ 'updated': undefined,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': {
+ 'currency': code,
+ 'cost': feeCost,
+ },
};
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- let url = '/api/' + this.version + '/' + this.implodeParams (path, params);
- const query = this.omit (params, this.extractParams (path));
+ let url = '';
+ let query = params;
+ const accountCategory = (api === 'accountCategory');
+ if (accountCategory || (api === 'accountGroup')) {
+ url += this.implodeParams ('/{account-group}', params);
+ query = this.omit (params, 'account-group');
+ }
+ const request = this.implodeParams (path, query);
+ url += '/api/pro/' + this.version;
+ if (accountCategory) {
+ url += this.implodeParams ('/{account-category}', query);
+ query = this.omit (query, 'account-category');
+ }
+ url += '/' + request;
+ query = this.omit (query, this.extractParams (path));
if (api === 'public') {
if (Object.keys (query).length) {
url += '?' + this.urlencode (query);
}
} else {
this.checkRequiredCredentials ();
- let accountGroup = this.safeString (this.options, 'accountGroup');
- if (accountGroup === undefined) {
- if (this.accounts !== undefined) {
- accountGroup = this.accounts[0]['id'];
- }
- }
- if (accountGroup !== undefined) {
- url = '/' + accountGroup + url;
- }
- const coid = this.safeString (query, 'coid');
- query['time'] = this.milliseconds ().toString ();
- let auth = query['time'] + '+' + path.replace ('/{coid}', ''); // fix sign error
+ const timestamp = this.milliseconds ().toString ();
+ const payload = timestamp + '+' + request;
+ const hmac = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'base64');
headers = {
'x-auth-key': this.apiKey,
- 'x-auth-timestamp': query['time'],
- 'Content-Type': 'application/json',
+ 'x-auth-timestamp': timestamp,
+ 'x-auth-signature': hmac,
};
- if (coid !== undefined) {
- auth += '+' + coid;
- headers['x-auth-coid'] = coid;
- }
- const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256', 'base64');
- headers['x-auth-signature'] = this.decode (signature);
if (method === 'GET') {
if (Object.keys (query).length) {
url += '?' + this.urlencode (query);
}
} else {
+ headers['Content-Type'] = 'application/json';
body = this.json (query);
}
}
@@ -20000,9 +24653,10 @@ module.exports = class bitmax extends Exchange {
return; // fallback to default error handler
}
//
- // {"code":2100,"message":"ApiKeyFailure"}
// {'code': 6010, 'message': 'Not enough balance.'}
// {'code': 60060, 'message': 'The order is already filled or canceled.'}
+ // {"code":2100,"message":"ApiKeyFailure"}
+ // {"code":300001,"message":"Price is too low from market price.","reason":"INVALID_PRICE","accountId":"cshrHKLZCjlZ2ejqkmvIHHtPmLYqdnda","ac":"CASH","action":"place-order","status":"Err","info":{"symbol":"BTC/USDT"}}
//
const code = this.safeString (response, 'code');
const message = this.safeString (response, 'message');
@@ -20017,7 +24671,7 @@ module.exports = class bitmax extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],39:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],38:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -20039,17 +24693,26 @@ module.exports = class bitmex extends Exchange {
'rateLimit': 2000,
'pro': true,
'has': {
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': false,
- 'fetchOHLCV': true,
- 'withdraw': true,
+ 'createOrder': true,
'editOrder': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchMyTrades': true,
'fetchLedger': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTransactions': 'emulated',
+ 'withdraw': true,
},
'timeframes': {
'1m': '1m',
@@ -20119,6 +24782,7 @@ module.exports = class bitmex extends Exchange {
'user/checkReferralCode',
'user/commission',
'user/depositAddress',
+ 'user/executionHistory',
'user/margin',
'user/minWithdrawalFee',
'user/wallet',
@@ -20176,6 +24840,7 @@ module.exports = class bitmex extends Exchange {
'overloaded': ExchangeNotAvailable,
'Account has insufficient Available Balance': InsufficientFunds,
'Service unavailable': ExchangeNotAvailable, // {"error":{"message":"Service unavailable","name":"HTTPError"}}
+ 'Server Error': ExchangeError, // {"error":{"message":"Server Error","name":"HTTPError"}}
},
},
'precisionMode': TICK_SIZE,
@@ -20273,29 +24938,133 @@ module.exports = class bitmex extends Exchange {
return result;
}
- async fetchBalance (params = {}) {
- await this.loadMarkets ();
- const request = {
- 'currency': 'all',
- };
- const response = await this.privateGetUserMargin (this.extend (request, params));
+ parseBalanceResponse (response) {
+ //
+ // [
+ // {
+ // "account":1455728,
+ // "currency":"XBt",
+ // "riskLimit":1000000000000,
+ // "prevState":"",
+ // "state":"",
+ // "action":"",
+ // "amount":263542,
+ // "pendingCredit":0,
+ // "pendingDebit":0,
+ // "confirmedDebit":0,
+ // "prevRealisedPnl":0,
+ // "prevUnrealisedPnl":0,
+ // "grossComm":0,
+ // "grossOpenCost":0,
+ // "grossOpenPremium":0,
+ // "grossExecCost":0,
+ // "grossMarkValue":0,
+ // "riskValue":0,
+ // "taxableMargin":0,
+ // "initMargin":0,
+ // "maintMargin":0,
+ // "sessionMargin":0,
+ // "targetExcessMargin":0,
+ // "varMargin":0,
+ // "realisedPnl":0,
+ // "unrealisedPnl":0,
+ // "indicativeTax":0,
+ // "unrealisedProfit":0,
+ // "syntheticMargin":null,
+ // "walletBalance":263542,
+ // "marginBalance":263542,
+ // "marginBalancePcnt":1,
+ // "marginLeverage":0,
+ // "marginUsedPcnt":0,
+ // "excessMargin":263542,
+ // "excessMarginPcnt":1,
+ // "availableMargin":263542,
+ // "withdrawableMargin":263542,
+ // "timestamp":"2020-08-03T12:01:01.246Z",
+ // "grossLastValue":0,
+ // "commission":null
+ // }
+ // ]
+ //
const result = { 'info': response };
for (let i = 0; i < response.length; i++) {
const balance = response[i];
const currencyId = this.safeString (balance, 'currency');
const code = this.safeCurrencyCode (currencyId);
const account = this.account ();
- account['free'] = this.safeFloat (balance, 'availableMargin');
- account['total'] = this.safeFloat (balance, 'marginBalance');
+ let free = this.safeFloat (balance, 'availableMargin');
+ let total = this.safeFloat (balance, 'marginBalance');
if (code === 'BTC') {
- account['free'] = account['free'] * 0.00000001;
- account['total'] = account['total'] * 0.00000001;
+ if (free !== undefined) {
+ free /= 100000000;
+ }
+ if (total !== undefined) {
+ total /= 100000000;
+ }
}
+ account['free'] = free;
+ account['total'] = total;
result[code] = account;
}
return this.parseBalance (result);
}
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'currency': 'all',
+ };
+ const response = await this.privateGetUserMargin (this.extend (request, params));
+ //
+ // [
+ // {
+ // "account":1455728,
+ // "currency":"XBt",
+ // "riskLimit":1000000000000,
+ // "prevState":"",
+ // "state":"",
+ // "action":"",
+ // "amount":263542,
+ // "pendingCredit":0,
+ // "pendingDebit":0,
+ // "confirmedDebit":0,
+ // "prevRealisedPnl":0,
+ // "prevUnrealisedPnl":0,
+ // "grossComm":0,
+ // "grossOpenCost":0,
+ // "grossOpenPremium":0,
+ // "grossExecCost":0,
+ // "grossMarkValue":0,
+ // "riskValue":0,
+ // "taxableMargin":0,
+ // "initMargin":0,
+ // "maintMargin":0,
+ // "sessionMargin":0,
+ // "targetExcessMargin":0,
+ // "varMargin":0,
+ // "realisedPnl":0,
+ // "unrealisedPnl":0,
+ // "indicativeTax":0,
+ // "unrealisedProfit":0,
+ // "syntheticMargin":null,
+ // "walletBalance":263542,
+ // "marginBalance":263542,
+ // "marginBalancePcnt":1,
+ // "marginLeverage":0,
+ // "marginUsedPcnt":0,
+ // "excessMargin":263542,
+ // "excessMarginPcnt":1,
+ // "availableMargin":263542,
+ // "withdrawableMargin":263542,
+ // "timestamp":"2020-08-03T12:01:01.246Z",
+ // "grossLastValue":0,
+ // "commission":null
+ // }
+ // ]
+ //
+ return this.parseBalanceResponse (response);
+ }
+
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -20525,7 +25294,7 @@ module.exports = class bitmex extends Exchange {
const code = this.safeCurrencyCode (currencyId, currency);
let amount = this.safeFloat (item, 'amount');
if (amount !== undefined) {
- amount = amount * 1e-8;
+ amount = amount / 100000000;
}
let timestamp = this.parse8601 (this.safeString (item, 'transactTime'));
if (timestamp === undefined) {
@@ -20536,7 +25305,7 @@ module.exports = class bitmex extends Exchange {
}
let feeCost = this.safeFloat (item, 'fee', 0);
if (feeCost !== undefined) {
- feeCost = feeCost * 1e-8;
+ feeCost = feeCost / 100000000;
}
const fee = {
'cost': feeCost,
@@ -20544,7 +25313,7 @@ module.exports = class bitmex extends Exchange {
};
let after = this.safeFloat (item, 'walletBalance');
if (after !== undefined) {
- after = after * 1e-8;
+ after = after / 100000000;
}
const before = this.sum (after, -amount);
let direction = undefined;
@@ -20682,11 +25451,11 @@ module.exports = class bitmex extends Exchange {
}
let amount = this.safeInteger (transaction, 'amount');
if (amount !== undefined) {
- amount = Math.abs (amount) * 1e-8;
+ amount = Math.abs (amount) / 10000000;
}
let feeCost = this.safeInteger (transaction, 'fee');
if (feeCost !== undefined) {
- feeCost = feeCost * 1e-8;
+ feeCost = feeCost / 10000000;
}
const fee = {
'cost': feeCost,
@@ -20744,7 +25513,7 @@ module.exports = class bitmex extends Exchange {
result[symbol] = ticker;
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
parseTicker (ticker, market = undefined) {
@@ -20895,10 +25664,26 @@ module.exports = class bitmex extends Exchange {
};
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
- const timestamp = this.parse8601 (this.safeString (ohlcv, 'timestamp'));
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "timestamp":"2015-09-25T13:38:00.000Z",
+ // "symbol":"XBTUSD",
+ // "open":237.45,
+ // "high":237.45,
+ // "low":237.45,
+ // "close":237.45,
+ // "trades":0,
+ // "volume":0,
+ // "vwap":null,
+ // "lastSize":null,
+ // "turnover":0,
+ // "homeNotional":0,
+ // "foreignNotional":0
+ // }
+ //
return [
- timestamp,
+ this.parse8601 (this.safeString (ohlcv, 'timestamp')),
this.safeFloat (ohlcv, 'open'),
this.safeFloat (ohlcv, 'high'),
this.safeFloat (ohlcv, 'low'),
@@ -20939,8 +25724,17 @@ module.exports = class bitmex extends Exchange {
}
const ymdhms = this.ymdhms (timestamp);
request['startTime'] = ymdhms; // starting date filter for results
+ } else {
+ request['reverse'] = true;
}
const response = await this.publicGetTradeBucketed (this.extend (request, params));
+ //
+ // [
+ // {"timestamp":"2015-09-25T13:38:00.000Z","symbol":"XBTUSD","open":237.45,"high":237.45,"low":237.45,"close":237.45,"trades":0,"volume":0,"vwap":null,"lastSize":null,"turnover":0,"homeNotional":0,"foreignNotional":0},
+ // {"timestamp":"2015-09-25T13:39:00.000Z","symbol":"XBTUSD","open":237.45,"high":237.45,"low":237.45,"close":237.45,"trades":0,"volume":0,"vwap":null,"lastSize":null,"turnover":0,"homeNotional":0,"foreignNotional":0},
+ // {"timestamp":"2015-09-25T13:40:00.000Z","symbol":"XBTUSD","open":237.45,"high":237.45,"low":237.45,"close":237.45,"trades":0,"volume":0,"vwap":null,"lastSize":null,"turnover":0,"homeNotional":0,"foreignNotional":0}
+ // ]
+ //
const result = this.parseOHLCVs (response, market, timeframe, since, limit);
if (fetchOHLCVOpenTimestamp) {
// bitmex returns the candle's close timestamp - https://github.com/ccxt/ccxt/issues/4446
@@ -21023,7 +25817,7 @@ module.exports = class bitmex extends Exchange {
// }
//
const timestamp = this.parse8601 (this.safeString (trade, 'timestamp'));
- const price = this.safeFloat (trade, 'price');
+ const price = this.safeFloat2 (trade, 'avgPx', 'price');
const amount = this.safeFloat2 (trade, 'size', 'lastQty');
const id = this.safeString (trade, 'trdMatchID');
const order = this.safeString (trade, 'orderID');
@@ -21050,16 +25844,8 @@ module.exports = class bitmex extends Exchange {
if (fee !== undefined) {
takerOrMaker = (fee['cost'] < 0) ? 'maker' : 'taker';
}
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
- }
+ const symbol = this.safeSymbol (marketId, market);
const type = this.safeStringLower (trade, 'ordType');
return {
'info': trade,
@@ -21096,18 +25882,20 @@ module.exports = class bitmex extends Exchange {
return this.safeString (statuses, status, status);
}
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'Day': 'Day',
+ 'GoodTillCancel': 'GTC',
+ 'ImmediateOrCancel': 'IOC',
+ 'FillOrKill': 'FOK',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
+ }
+
parseOrder (order, market = undefined) {
const status = this.parseOrderStatus (this.safeString (order, 'ordStatus'));
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- } else {
- const marketId = this.safeString (order, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
- }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.parse8601 (this.safeString (order, 'timestamp'));
const lastTradeTimestamp = this.parse8601 (this.safeString (order, 'transactTime'));
const price = this.safeFloat (order, 'price');
@@ -21132,6 +25920,8 @@ module.exports = class bitmex extends Exchange {
const type = this.safeStringLower (order, 'ordType');
const side = this.safeStringLower (order, 'side');
const clientOrderId = this.safeString (order, 'clOrdID');
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'timeInForce'));
+ const stopPrice = this.safeFloat (order, 'stopPx');
return {
'info': order,
'id': id,
@@ -21141,8 +25931,10 @@ module.exports = class bitmex extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -21162,6 +25954,9 @@ module.exports = class bitmex extends Exchange {
};
if (since !== undefined) {
request['startTime'] = this.iso8601 (since);
+ } else {
+ // by default reverse=false, i.e. trades are fetched since the time of market inception (year 2015 for XBTUSD)
+ request['reverse'] = true;
}
if (limit !== undefined) {
request['count'] = limit;
@@ -21200,27 +25995,46 @@ module.exports = class bitmex extends Exchange {
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
+ const market = this.market (symbol);
+ const orderType = this.capitalize (type);
const request = {
- 'symbol': this.marketId (symbol),
+ 'symbol': market['id'],
'side': this.capitalize (side),
'orderQty': amount,
- 'ordType': this.capitalize (type),
+ 'ordType': orderType,
};
if (price !== undefined) {
- request['price'] = price;
+ if (orderType === 'Stop') {
+ const stopPrice = this.safeFloat2 (params, 'stopPx', 'stopPrice');
+ request['stopPx'] = stopPrice;
+ params = this.omit (params, [ 'stopPx', 'stopPrice' ]);
+ } else {
+ request['price'] = price;
+ }
+ }
+ const clientOrderId = this.safeString2 (params, 'clOrdID', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['clOrdID'] = clientOrderId;
+ params = this.omit (params, [ 'clOrdID', 'clientOrderId' ]);
}
const response = await this.privatePostOrder (this.extend (request, params));
- const order = this.parseOrder (response);
- const id = this.safeString (order, 'id');
- this.orders[id] = order;
- return this.extend ({ 'info': response }, order);
+ return this.parseOrder (response, market);
}
async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
await this.loadMarkets ();
- const request = {
- 'orderID': id,
- };
+ const request = {};
+ const origClOrdID = this.safeString2 (params, 'origClOrdID', 'clientOrderId');
+ if (origClOrdID !== undefined) {
+ request['origClOrdID'] = origClOrdID;
+ const clientOrderId = this.safeString (params, 'clOrdID', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['clOrdID'] = clientOrderId;
+ }
+ params = this.omit (params, [ 'origClOrdID', 'clOrdID', 'clientOrderId' ]);
+ } else {
+ request['orderID'] = id;
+ }
if (amount !== undefined) {
request['orderQty'] = amount;
}
@@ -21228,32 +26042,183 @@ module.exports = class bitmex extends Exchange {
request['price'] = price;
}
const response = await this.privatePutOrder (this.extend (request, params));
- const order = this.parseOrder (response);
- this.orders[order['id']] = order;
- return this.extend ({ 'info': response }, order);
+ return this.parseOrder (response);
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
// https://github.com/ccxt/ccxt/issues/6507
- const clOrdID = this.safeValue (params, 'clOrdID');
+ const clientOrderId = this.safeString2 (params, 'clOrdID', 'clientOrderId');
const request = {};
- if (clOrdID === undefined) {
+ if (clientOrderId === undefined) {
request['orderID'] = id;
} else {
- request['clOrdID'] = clOrdID;
+ request['clOrdID'] = clientOrderId;
+ params = this.omit (params, [ 'clOrdID', 'clientOrderId' ]);
}
const response = await this.privateDeleteOrder (this.extend (request, params));
- let order = response[0];
+ const order = this.safeValue (response, 0, {});
const error = this.safeString (order, 'error');
if (error !== undefined) {
if (error.indexOf ('Unable to cancel order due to existing state') >= 0) {
throw new OrderNotFound (this.id + ' cancelOrder() failed: ' + error);
}
}
- order = this.parseOrder (order);
- this.orders[order['id']] = order;
- return this.extend ({ 'info': response }, order);
+ return this.parseOrder (order);
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ const response = await this.privateDeleteOrderAll (this.extend (request, params));
+ //
+ // [
+ // {
+ // "orderID": "string",
+ // "clOrdID": "string",
+ // "clOrdLinkID": "string",
+ // "account": 0,
+ // "symbol": "string",
+ // "side": "string",
+ // "simpleOrderQty": 0,
+ // "orderQty": 0,
+ // "price": 0,
+ // "displayQty": 0,
+ // "stopPx": 0,
+ // "pegOffsetValue": 0,
+ // "pegPriceType": "string",
+ // "currency": "string",
+ // "settlCurrency": "string",
+ // "ordType": "string",
+ // "timeInForce": "string",
+ // "execInst": "string",
+ // "contingencyType": "string",
+ // "exDestination": "string",
+ // "ordStatus": "string",
+ // "triggered": "string",
+ // "workingIndicator": true,
+ // "ordRejReason": "string",
+ // "simpleLeavesQty": 0,
+ // "leavesQty": 0,
+ // "simpleCumQty": 0,
+ // "cumQty": 0,
+ // "avgPx": 0,
+ // "multiLegReportingType": "string",
+ // "text": "string",
+ // "transactTime": "2020-06-01T09:36:35.290Z",
+ // "timestamp": "2020-06-01T09:36:35.290Z"
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market);
+ }
+
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetPosition (params);
+ // [
+ // {
+ // "account": 0,
+ // "symbol": "string",
+ // "currency": "string",
+ // "underlying": "string",
+ // "quoteCurrency": "string",
+ // "commission": 0,
+ // "initMarginReq": 0,
+ // "maintMarginReq": 0,
+ // "riskLimit": 0,
+ // "leverage": 0,
+ // "crossMargin": true,
+ // "deleveragePercentile": 0,
+ // "rebalancedPnl": 0,
+ // "prevRealisedPnl": 0,
+ // "prevUnrealisedPnl": 0,
+ // "prevClosePrice": 0,
+ // "openingTimestamp": "2020-11-09T06:53:59.892Z",
+ // "openingQty": 0,
+ // "openingCost": 0,
+ // "openingComm": 0,
+ // "openOrderBuyQty": 0,
+ // "openOrderBuyCost": 0,
+ // "openOrderBuyPremium": 0,
+ // "openOrderSellQty": 0,
+ // "openOrderSellCost": 0,
+ // "openOrderSellPremium": 0,
+ // "execBuyQty": 0,
+ // "execBuyCost": 0,
+ // "execSellQty": 0,
+ // "execSellCost": 0,
+ // "execQty": 0,
+ // "execCost": 0,
+ // "execComm": 0,
+ // "currentTimestamp": "2020-11-09T06:53:59.893Z",
+ // "currentQty": 0,
+ // "currentCost": 0,
+ // "currentComm": 0,
+ // "realisedCost": 0,
+ // "unrealisedCost": 0,
+ // "grossOpenCost": 0,
+ // "grossOpenPremium": 0,
+ // "grossExecCost": 0,
+ // "isOpen": true,
+ // "markPrice": 0,
+ // "markValue": 0,
+ // "riskValue": 0,
+ // "homeNotional": 0,
+ // "foreignNotional": 0,
+ // "posState": "string",
+ // "posCost": 0,
+ // "posCost2": 0,
+ // "posCross": 0,
+ // "posInit": 0,
+ // "posComm": 0,
+ // "posLoss": 0,
+ // "posMargin": 0,
+ // "posMaint": 0,
+ // "posAllowance": 0,
+ // "taxableMargin": 0,
+ // "initMargin": 0,
+ // "maintMargin": 0,
+ // "sessionMargin": 0,
+ // "targetExcessMargin": 0,
+ // "varMargin": 0,
+ // "realisedGrossPnl": 0,
+ // "realisedTax": 0,
+ // "realisedPnl": 0,
+ // "unrealisedGrossPnl": 0,
+ // "longBankrupt": 0,
+ // "shortBankrupt": 0,
+ // "taxBase": 0,
+ // "indicativeTaxRate": 0,
+ // "indicativeTax": 0,
+ // "unrealisedTax": 0,
+ // "unrealisedPnl": 0,
+ // "unrealisedPnlPcnt": 0,
+ // "unrealisedRoePcnt": 0,
+ // "simpleQty": 0,
+ // "simpleCost": 0,
+ // "simpleValue": 0,
+ // "simplePnl": 0,
+ // "simplePnlPcnt": 0,
+ // "avgCostPrice": 0,
+ // "avgEntryPrice": 0,
+ // "breakEvenPrice": 0,
+ // "marginCallPrice": 0,
+ // "liquidationPrice": 0,
+ // "bankruptPrice": 0,
+ // "timestamp": "2020-11-09T06:53:59.894Z",
+ // "lastPrice": 0,
+ // "lastValue": 0
+ // }
+ // ]
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
}
isFiat (currency) {
@@ -21283,7 +26248,7 @@ module.exports = class bitmex extends Exchange {
const response = await this.privatePostUserRequestWithdrawal (this.extend (request, params));
return {
'info': response,
- 'id': response['transactID'],
+ 'id': this.safeString (response, 'transactID'),
};
}
@@ -21348,13 +26313,1827 @@ module.exports = class bitmex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],40:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],39:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { AuthenticationError, ExchangeError, PermissionDenied, BadRequest, ArgumentsRequired, OrderNotFound, InsufficientFunds, ExchangeNotAvailable, DDoSProtection, InvalidAddress, InvalidOrder } = require ('./base/errors');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class bitpanda extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'bitpanda',
+ 'name': 'Bitpanda Pro',
+ 'countries': [ 'AT' ], // Austria
+ 'rateLimit': 300,
+ 'version': 'v1',
+ // new metainfo interface
+ 'has': {
+ 'CORS': false,
+ 'publicAPI': true,
+ 'privateAPI': true,
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'cancelOrders': true,
+ 'createDepositAddress': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchDeposits': true,
+ 'fetchDepositAddress': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrderTrades': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchTradingFees': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
+ },
+ 'timeframes': {
+ '1m': '1/MINUTES',
+ '5m': '5/MINUTES',
+ '15m': '15/MINUTES',
+ '30m': '30/MINUTES',
+ '1h': '1/HOURS',
+ '4h': '4/HOURS',
+ '1d': '1/DAYS',
+ '1w': '1/WEEKS',
+ '1M': '1/MONTHS',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87591171-9a377d80-c6f0-11ea-94ac-97a126eac3bc.jpg',
+ 'api': {
+ 'public': 'https://api.exchange.bitpanda.com/public',
+ 'private': 'https://api.exchange.bitpanda.com/public',
+ },
+ 'www': 'https://www.bitpanda.com/en/pro',
+ 'doc': [
+ 'https://developers.bitpanda.com/exchange/',
+ ],
+ 'fees': 'https://www.bitpanda.com/en/pro/fees',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'currencies',
+ 'candlesticks/{instrument_code}',
+ 'fees',
+ 'instruments',
+ 'order-book/{instrument_code}',
+ 'market-ticker',
+ 'market-ticker/{instrument_code}',
+ 'price-ticks/{instrument_code}',
+ 'time',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'account/balances',
+ 'account/deposit/crypto/{currency_code}',
+ 'account/deposit/fiat/EUR',
+ 'account/deposits',
+ 'account/deposits/bitpanda',
+ 'account/withdrawals',
+ 'account/withdrawals/bitpanda',
+ 'account/fees',
+ 'account/orders',
+ 'account/orders/{order_id}',
+ 'account/orders/{order_id}/trades',
+ 'account/trades',
+ 'account/trades/{trade_id}',
+ 'account/trading-volume',
+ ],
+ 'post': [
+ 'account/deposit/crypto',
+ 'account/withdraw/crypto',
+ 'account/withdraw/fiat',
+ 'account/fees',
+ 'account/orders',
+ ],
+ 'delete': [
+ 'account/orders',
+ 'account/orders/{order_id}',
+ 'account/orders/client/{client_id}',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.15 / 100,
+ 'maker': 0.10 / 100,
+ 'tiers': [
+ // volume in BTC
+ {
+ 'taker': [
+ [0, 0.15 / 100],
+ [100, 0.13 / 100],
+ [250, 0.13 / 100],
+ [1000, 0.1 / 100],
+ [5000, 0.09 / 100],
+ [10000, 0.075 / 100],
+ [20000, 0.065 / 100],
+ ],
+ 'maker': [
+ [0, 0.1 / 100],
+ [100, 0.1 / 100],
+ [250, 0.09 / 100],
+ [1000, 0.075 / 100],
+ [5000, 0.06 / 100],
+ [10000, 0.05 / 100],
+ [20000, 0.05 / 100],
+ ],
+ },
+ ],
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': false,
+ },
+ 'exceptions': {
+ 'exact': {
+ 'INVALID_CLIENT_UUID': InvalidOrder,
+ 'ORDER_NOT_FOUND': OrderNotFound,
+ 'ONLY_ONE_ERC20_ADDRESS_ALLOWED': InvalidAddress,
+ 'DEPOSIT_ADDRESS_NOT_USED': InvalidAddress,
+ 'INVALID_CREDENTIALS': AuthenticationError,
+ 'MISSING_CREDENTIALS': AuthenticationError,
+ 'INVALID_APIKEY': AuthenticationError,
+ 'INVALID_SCOPES': AuthenticationError,
+ 'INVALID_SUBJECT': AuthenticationError,
+ 'INVALID_ISSUER': AuthenticationError,
+ 'INVALID_AUDIENCE': AuthenticationError,
+ 'INVALID_DEVICE_ID': AuthenticationError,
+ 'INVALID_IP_RESTRICTION': AuthenticationError,
+ 'APIKEY_REVOKED': AuthenticationError,
+ 'APIKEY_EXPIRED': AuthenticationError,
+ 'SYNCHRONIZER_TOKEN_MISMATCH': AuthenticationError,
+ 'SESSION_EXPIRED': AuthenticationError,
+ 'INTERNAL_ERROR': AuthenticationError,
+ 'CLIENT_IP_BLOCKED': PermissionDenied,
+ 'MISSING_PERMISSION': PermissionDenied,
+ 'ILLEGAL_CHARS': BadRequest,
+ 'UNSUPPORTED_MEDIA_TYPE': BadRequest,
+ 'ACCOUNT_HISTORY_TIME_RANGE_TOO_BIG': BadRequest,
+ 'CANDLESTICKS_TIME_RANGE_TOO_BIG': BadRequest,
+ 'INVALID_INSTRUMENT_CODE': BadRequest,
+ 'INVALID_ORDER_TYPE': BadRequest,
+ 'INVALID_UNIT': BadRequest,
+ 'INVALID_PERIOD': BadRequest,
+ 'INVALID_TIME': BadRequest,
+ 'INVALID_DATE': BadRequest,
+ 'INVALID_CURRENCY': BadRequest,
+ 'INVALID_AMOUNT': BadRequest,
+ 'INVALID_PRICE': BadRequest,
+ 'INVALID_LIMIT': BadRequest,
+ 'INVALID_QUERY': BadRequest,
+ 'INVALID_CURSOR': BadRequest,
+ 'INVALID_ACCOUNT_ID': BadRequest,
+ 'INVALID_SIDE': InvalidOrder,
+ 'INVALID_ACCOUNT_HISTORY_FROM_TIME': BadRequest,
+ 'INVALID_ACCOUNT_HISTORY_MAX_PAGE_SIZE': BadRequest,
+ 'INVALID_ACCOUNT_HISTORY_TIME_PERIOD': BadRequest,
+ 'INVALID_ACCOUNT_HISTORY_TO_TIME': BadRequest,
+ 'INVALID_CANDLESTICKS_GRANULARITY': BadRequest,
+ 'INVALID_CANDLESTICKS_UNIT': BadRequest,
+ 'INVALID_ORDER_BOOK_DEPTH': BadRequest,
+ 'INVALID_ORDER_BOOK_LEVEL': BadRequest,
+ 'INVALID_PAGE_CURSOR': BadRequest,
+ 'INVALID_TIME_RANGE': BadRequest,
+ 'INVALID_TRADE_ID': BadRequest,
+ 'INVALID_UI_ACCOUNT_SETTINGS': BadRequest,
+ 'NEGATIVE_AMOUNT': InvalidOrder,
+ 'NEGATIVE_PRICE': InvalidOrder,
+ 'MIN_SIZE_NOT_SATISFIED': InvalidOrder,
+ 'BAD_AMOUNT_PRECISION': InvalidOrder,
+ 'BAD_PRICE_PRECISION': InvalidOrder,
+ 'BAD_TRIGGER_PRICE_PRECISION': InvalidOrder,
+ 'MAX_OPEN_ORDERS_EXCEEDED': BadRequest,
+ 'MISSING_PRICE': InvalidOrder,
+ 'MISSING_ORDER_TYPE': InvalidOrder,
+ 'MISSING_SIDE': InvalidOrder,
+ 'MISSING_CANDLESTICKS_PERIOD_PARAM': ArgumentsRequired,
+ 'MISSING_CANDLESTICKS_UNIT_PARAM': ArgumentsRequired,
+ 'MISSING_FROM_PARAM': ArgumentsRequired,
+ 'MISSING_INSTRUMENT_CODE': ArgumentsRequired,
+ 'MISSING_ORDER_ID': InvalidOrder,
+ 'MISSING_TO_PARAM': ArgumentsRequired,
+ 'MISSING_TRADE_ID': ArgumentsRequired,
+ 'INVALID_ORDER_ID': OrderNotFound,
+ 'NOT_FOUND': OrderNotFound,
+ 'INSUFFICIENT_LIQUIDITY': InsufficientFunds,
+ 'INSUFFICIENT_FUNDS': InsufficientFunds,
+ 'NO_TRADING': ExchangeNotAvailable,
+ 'SERVICE_UNAVAILABLE': ExchangeNotAvailable,
+ 'GATEWAY_TIMEOUT': ExchangeNotAvailable,
+ 'RATELIMIT': DDoSProtection,
+ 'CF_RATELIMIT': DDoSProtection,
+ 'INTERNAL_SERVER_ERROR': ExchangeError,
+ },
+ 'broad': {
+ },
+ },
+ 'commonCurrencies': {
+ 'MIOTA': 'IOTA', // https://github.com/ccxt/ccxt/issues/7487
+ },
+ // exchange-specific options
+ 'options': {
+ 'fetchTradingFees': {
+ 'method': 'fetchPrivateTradingFees', // or 'fetchPublicTradingFees'
+ },
+ 'fiat': [ 'EUR', 'CHF' ],
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // {
+ // iso: '2020-07-10T05:17:26.716Z',
+ // epoch_millis: 1594358246716,
+ // }
+ //
+ return this.safeInteger (response, 'epoch_millis');
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCurrencies (params);
+ //
+ // [
+ // {
+ // "code":"BEST",
+ // "precision":8
+ // }
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const currency = response[i];
+ const id = this.safeString (currency, 'code');
+ const code = this.safeCurrencyCode (id);
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'name': undefined,
+ 'info': currency, // the original payload
+ 'active': undefined,
+ 'fee': undefined,
+ 'precision': this.safeInteger (currency, 'precision'),
+ 'limits': {
+ 'amount': { 'min': undefined, 'max': undefined },
+ 'price': { 'min': undefined, 'max': undefined },
+ 'cost': { 'min': undefined, 'max': undefined },
+ 'withdraw': { 'min': undefined, 'max': undefined },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetInstruments (params);
+ //
+ // [
+ // {
+ // state: 'ACTIVE',
+ // base: { code: 'ETH', precision: 8 },
+ // quote: { code: 'CHF', precision: 2 },
+ // amount_precision: 4,
+ // market_precision: 2,
+ // min_size: '10.0'
+ // }
+ // ]
+ //
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ const baseAsset = this.safeValue (market, 'base', {});
+ const quoteAsset = this.safeValue (market, 'quote', {});
+ const baseId = this.safeString (baseAsset, 'code');
+ const quoteId = this.safeString (quoteAsset, 'code');
+ const id = baseId + '_' + quoteId;
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const precision = {
+ 'amount': this.safeInteger (market, 'amount_precision'),
+ 'price': this.safeInteger (market, 'market_precision'),
+ };
+ const limits = {
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': this.safeFloat (market, 'min_size'),
+ 'max': undefined,
+ },
+ };
+ const state = this.safeString (market, 'state');
+ const active = (state === 'ACTIVE');
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'precision': precision,
+ 'limits': limits,
+ 'info': market,
+ 'active': active,
+ });
+ }
+ return result;
+ }
+
+ async fetchTradingFees (params = {}) {
+ let method = this.safeString (params, 'method');
+ params = this.omit (params, 'method');
+ if (method === undefined) {
+ const options = this.safeValue (this.options, 'fetchTradingFees', {});
+ method = this.safeString (options, 'method', 'fetchPrivateTradingFees');
+ }
+ return await this[method] (params);
+ }
+
+ async fetchPublicTradingFees (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetFees (params);
+ //
+ // [
+ // {
+ // "fee_group_id":"default",
+ // "display_text":"The standard fee plan.",
+ // "fee_tiers":[
+ // {"volume":"0.0","fee_group_id":"default","maker_fee":"0.1","taker_fee":"0.15"},
+ // {"volume":"100.0","fee_group_id":"default","maker_fee":"0.1","taker_fee":"0.13"},
+ // {"volume":"250.0","fee_group_id":"default","maker_fee":"0.09","taker_fee":"0.13"},
+ // {"volume":"1000.0","fee_group_id":"default","maker_fee":"0.075","taker_fee":"0.1"},
+ // {"volume":"5000.0","fee_group_id":"default","maker_fee":"0.06","taker_fee":"0.09"},
+ // {"volume":"10000.0","fee_group_id":"default","maker_fee":"0.05","taker_fee":"0.075"},
+ // {"volume":"20000.0","fee_group_id":"default","maker_fee":"0.05","taker_fee":"0.065"}
+ // ],
+ // "fee_discount_rate":"25.0",
+ // "minimum_price_value":"0.12"
+ // }
+ // ]
+ //
+ const feeGroupsById = this.indexBy (response, 'fee_group_id');
+ const feeGroupId = this.safeValue (this.options, 'fee_group_id', 'default');
+ const feeGroup = this.safeValue (feeGroupsById, feeGroupId, {});
+ const feeTiers = this.safeValue (feeGroup, 'fee_tiers');
+ const result = {};
+ for (let i = 0; i < this.symbols.length; i++) {
+ const symbol = this.symbols[i];
+ const fee = {
+ 'info': feeGroup,
+ 'symbol': symbol,
+ 'maker': undefined,
+ 'taker': undefined,
+ 'percentage': true,
+ 'tierBased': true,
+ };
+ const takerFees = [];
+ const makerFees = [];
+ for (let i = 0; i < feeTiers.length; i++) {
+ const tier = feeTiers[i];
+ const volume = this.safeFloat (tier, 'volume');
+ let taker = this.safeFloat (tier, 'taker_fee');
+ let maker = this.safeFloat (tier, 'maker_fee');
+ taker /= 100;
+ maker /= 100;
+ takerFees.push ([ volume, taker ]);
+ makerFees.push ([ volume, maker ]);
+ if (i === 0) {
+ fee['taker'] = taker;
+ fee['maker'] = maker;
+ }
+ }
+ const tiers = {
+ 'taker': takerFees,
+ 'maker': makerFees,
+ };
+ fee['tiers'] = tiers;
+ result[symbol] = fee;
+ }
+ return result;
+ }
+
+ async fetchPrivateTradingFees (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccountFees (params);
+ //
+ // {
+ // "account_id": "ed524d00-820a-11e9-8f1e-69602df16d85",
+ // "running_trading_volume": "0.0",
+ // "fee_group_id": "default",
+ // "collect_fees_in_best": false,
+ // "fee_discount_rate": "25.0",
+ // "minimum_price_value": "0.12",
+ // "fee_tiers": [
+ // { "volume": "0.0", "fee_group_id": "default", "maker_fee": "0.1", "taker_fee": "0.1" },
+ // { "volume": "100.0", "fee_group_id": "default", "maker_fee": "0.09", "taker_fee": "0.1" },
+ // { "volume": "250.0", "fee_group_id": "default", "maker_fee": "0.08", "taker_fee": "0.1" },
+ // { "volume": "1000.0", "fee_group_id": "default", "maker_fee": "0.07", "taker_fee": "0.09" },
+ // { "volume": "5000.0", "fee_group_id": "default", "maker_fee": "0.06", "taker_fee": "0.08" },
+ // { "volume": "10000.0", "fee_group_id": "default", "maker_fee": "0.05", "taker_fee": "0.07" },
+ // { "volume": "20000.0", "fee_group_id": "default", "maker_fee": "0.05", "taker_fee": "0.06" },
+ // { "volume": "50000.0", "fee_group_id": "default", "maker_fee": "0.05", "taker_fee": "0.05" }
+ // ],
+ // "active_fee_tier": { "volume": "0.0", "fee_group_id": "default", "maker_fee": "0.1", "taker_fee": "0.1" }
+ // }
+ //
+ const activeFeeTier = this.safeValue (response, 'active_fee_tier', {});
+ const result = {
+ 'info': response,
+ 'maker': this.safeFloat (activeFeeTier, 'maker_fee'),
+ 'taker': this.safeFloat (activeFeeTier, 'taker_fee'),
+ 'percentage': true,
+ 'tierBased': true,
+ };
+ const feeTiers = this.safeValue (response, 'fee_tiers');
+ const takerFees = [];
+ const makerFees = [];
+ for (let i = 0; i < feeTiers.length; i++) {
+ const tier = feeTiers[i];
+ const volume = this.safeFloat (tier, 'volume');
+ let taker = this.safeFloat (tier, 'taker_fee');
+ let maker = this.safeFloat (tier, 'maker_fee');
+ taker /= 100;
+ maker /= 100;
+ takerFees.push ([ volume, taker ]);
+ makerFees.push ([ volume, maker ]);
+ }
+ const tiers = {
+ 'taker': takerFees,
+ 'maker': makerFees,
+ };
+ result['tiers'] = tiers;
+ return result;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker, fetchTickers
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "sequence":602562,
+ // "time":"2020-07-10T06:27:34.951Z",
+ // "state":"ACTIVE",
+ // "is_frozen":0,
+ // "quote_volume":"1695555.1783768",
+ // "base_volume":"205.67436",
+ // "last_price":"8143.91",
+ // "best_bid":"8143.71",
+ // "best_ask":"8156.9",
+ // "price_change":"-147.47",
+ // "price_change_percentage":"-1.78",
+ // "high":"8337.45",
+ // "low":"8110.0"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (ticker, 'time'));
+ const marketId = this.safeString (ticker, 'instrument_code');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const last = this.safeFloat (ticker, 'last_price');
+ const percentage = this.safeFloat (ticker, 'price_change_percentage');
+ const change = this.safeFloat (ticker, 'price_change');
+ let open = undefined;
+ let average = undefined;
+ if ((last !== undefined) && (change !== undefined)) {
+ open = last - change;
+ average = this.sum (last, open) / 2;
+ }
+ const baseVolume = this.safeFloat (ticker, 'base_volume');
+ const quoteVolume = this.safeFloat (ticker, 'quote_volume');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': this.safeFloat (ticker, 'best_bid'),
+ 'bidVolume': undefined,
+ 'ask': this.safeFloat (ticker, 'best_ask'),
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'instrument_code': market['id'],
+ };
+ const response = await this.publicGetMarketTickerInstrumentCode (this.extend (request, params));
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "sequence":602562,
+ // "time":"2020-07-10T06:27:34.951Z",
+ // "state":"ACTIVE",
+ // "is_frozen":0,
+ // "quote_volume":"1695555.1783768",
+ // "base_volume":"205.67436",
+ // "last_price":"8143.91",
+ // "best_bid":"8143.71",
+ // "best_ask":"8156.9",
+ // "price_change":"-147.47",
+ // "price_change_percentage":"-1.78",
+ // "high":"8337.45",
+ // "low":"8110.0"
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetMarketTicker (params);
+ //
+ // [
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "sequence":602562,
+ // "time":"2020-07-10T06:27:34.951Z",
+ // "state":"ACTIVE",
+ // "is_frozen":0,
+ // "quote_volume":"1695555.1783768",
+ // "base_volume":"205.67436",
+ // "last_price":"8143.91",
+ // "best_bid":"8143.71",
+ // "best_ask":"8156.9",
+ // "price_change":"-147.47",
+ // "price_change_percentage":"-1.78",
+ // "high":"8337.45",
+ // "low":"8110.0"
+ // }
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const ticker = this.parseTicker (response[i]);
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'instrument_code': this.marketId (symbol),
+ // level 1 means only the best bid and ask
+ // level 2 is a compiled order book up to market precision
+ // level 3 is a full orderbook
+ // if you wish to get regular updates about orderbooks please use the Websocket channel
+ // heavy usage of this endpoint may result in limited access according to rate limits rules
+ // 'level': 3, // default
+ };
+ if (limit !== undefined) {
+ request['depth'] = limit;
+ }
+ const response = await this.publicGetOrderBookInstrumentCode (this.extend (request, params));
+ //
+ // level 1
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "time":"2020-07-10T07:39:06.343Z",
+ // "asks":{
+ // "value":{
+ // "price":"8145.29",
+ // "amount":"0.96538",
+ // "number_of_orders":1
+ // }
+ // },
+ // "bids":{
+ // "value":{
+ // "price":"8134.0",
+ // "amount":"1.5978",
+ // "number_of_orders":5
+ // }
+ // }
+ // }
+ //
+ // level 2
+ //
+ // {
+ // "instrument_code":"BTC_EUR","time":"2020-07-10T07:36:43.538Z",
+ // "asks":[
+ // {"price":"8146.59","amount":"0.89691","number_of_orders":1},
+ // {"price":"8146.89","amount":"1.92062","number_of_orders":1},
+ // {"price":"8169.5","amount":"0.0663","number_of_orders":1},
+ // ],
+ // "bids":[
+ // {"price":"8143.49","amount":"0.01329","number_of_orders":1},
+ // {"price":"8137.01","amount":"5.34748","number_of_orders":1},
+ // {"price":"8137.0","amount":"2.0","number_of_orders":1},
+ // ]
+ // }
+ //
+ // level 3
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "time":"2020-07-10T07:32:31.525Z",
+ // "bids":[
+ // {"price":"8146.79","amount":"0.01537","order_id":"5d717da1-a8f4-422d-afcc-03cb6ab66825"},
+ // {"price":"8139.32","amount":"3.66009","order_id":"d0715c68-f28d-4cf1-a450-d56cf650e11c"},
+ // {"price":"8137.51","amount":"2.61049","order_id":"085fd6f4-e835-4ca5-9449-a8f165772e60"},
+ // ],
+ // "asks":[
+ // {"price":"8153.49","amount":"0.93384","order_id":"755d3aa3-42b5-46fa-903d-98f42e9ae6c4"},
+ // {"price":"8153.79","amount":"1.80456","order_id":"62034cf3-b70d-45ff-b285-ba6307941e7c"},
+ // {"price":"8167.9","amount":"0.0018","order_id":"036354e0-71cd-492f-94f2-01f7d4b66422"},
+ // ]
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (response, 'time'));
+ return this.parseOrderBook (response, timestamp, 'bids', 'asks', 'price', 'amount');
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "granularity":{"unit":"HOURS","period":1},
+ // "high":"9252.65",
+ // "low":"9115.27",
+ // "open":"9250.0",
+ // "close":"9132.35",
+ // "total_amount":"33.85924",
+ // "volume":"311958.9635744",
+ // "time":"2020-05-08T22:59:59.999Z",
+ // "last_sequence":461123
+ // }
+ //
+ const granularity = this.safeValue (ohlcv, 'granularity');
+ const unit = this.safeString (granularity, 'unit');
+ const period = this.safeString (granularity, 'period');
+ const units = {
+ 'MINUTES': 'm',
+ 'HOURS': 'h',
+ 'DAYS': 'd',
+ 'WEEKS': 'w',
+ 'MONTHS': 'M',
+ };
+ const lowercaseUnit = this.safeString (units, unit);
+ const timeframe = period + lowercaseUnit;
+ const durationInSeconds = this.parseTimeframe (timeframe);
+ const duration = durationInSeconds * 1000;
+ const timestamp = this.parse8601 (this.safeString (ohlcv, 'time'));
+ const alignedTimestamp = duration * parseInt (timestamp / duration);
+ const options = this.safeValue (this.options, 'fetchOHLCV', {});
+ const volumeField = this.safeString (options, 'volume', 'total_amount');
+ return [
+ alignedTimestamp,
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, volumeField),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const periodUnit = this.safeString (this.timeframes, timeframe);
+ const [ period, unit ] = periodUnit.split ('/');
+ const durationInSeconds = this.parseTimeframe (timeframe);
+ const duration = durationInSeconds * 1000;
+ if (limit === undefined) {
+ limit = 1500;
+ }
+ const request = {
+ 'instrument_code': market['id'],
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()),
+ 'period': period,
+ 'unit': unit,
+ };
+ if (since === undefined) {
+ const now = this.milliseconds ();
+ request['to'] = this.iso8601 (now);
+ request['from'] = this.iso8601 (now - limit * duration);
+ } else {
+ request['from'] = this.iso8601 (since);
+ request['to'] = this.iso8601 (this.sum (since, limit * duration));
+ }
+ const response = await this.publicGetCandlesticksInstrumentCode (this.extend (request, params));
+ //
+ // [
+ // {"instrument_code":"BTC_EUR","granularity":{"unit":"HOURS","period":1},"high":"9252.65","low":"9115.27","open":"9250.0","close":"9132.35","total_amount":"33.85924","volume":"311958.9635744","time":"2020-05-08T22:59:59.999Z","last_sequence":461123},
+ // {"instrument_code":"BTC_EUR","granularity":{"unit":"HOURS","period":1},"high":"9162.49","low":"9040.0","open":"9132.53","close":"9083.69","total_amount":"26.19685","volume":"238553.7812365","time":"2020-05-08T23:59:59.999Z","last_sequence":461376},
+ // {"instrument_code":"BTC_EUR","granularity":{"unit":"HOURS","period":1},"high":"9135.7","low":"9002.59","open":"9055.45","close":"9133.98","total_amount":"26.21919","volume":"238278.8724959","time":"2020-05-09T00:59:59.999Z","last_sequence":461521},
+ // ]
+ //
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "price":"8137.28",
+ // "amount":"0.22269",
+ // "taker_side":"BUY",
+ // "volume":"1812.0908832",
+ // "time":"2020-07-10T14:44:32.299Z",
+ // "trade_timestamp":1594392272299,
+ // "sequence":603047
+ // }
+ //
+ // fetchMyTrades, fetchOrder, fetchOpenOrders, fetchClosedOrders trades (private)
+ //
+ // {
+ // "fee": {
+ // "fee_amount": "0.0014",
+ // "fee_currency": "BTC",
+ // "fee_percentage": "0.1",
+ // "fee_group_id": "default",
+ // "fee_type": "TAKER",
+ // "running_trading_volume": "0.0"
+ // },
+ // "trade": {
+ // "trade_id": "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
+ // "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "amount": "1.4",
+ // "side": "BUY",
+ // "instrument_code": "BTC_EUR",
+ // "price": "7341.4",
+ // "time": "2019-09-27T15:05:32.564Z",
+ // "sequence": 48670
+ // }
+ // }
+ //
+ const feeInfo = this.safeValue (trade, 'fee', {});
+ trade = this.safeValue (trade, 'trade', trade);
+ const timestamp = this.parse8601 (this.safeString (trade, 'time'));
+ const side = this.safeStringLower2 (trade, 'side', 'taker_side');
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'amount');
+ let cost = this.safeFloat (trade, 'volume');
+ if ((cost === undefined) && (amount !== undefined) && (price !== undefined)) {
+ cost = amount * price;
+ }
+ const marketId = this.safeString (trade, 'instrument_code');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const feeCost = this.safeFloat (feeInfo, 'fee_amount');
+ let takerOrMaker = undefined;
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (feeInfo, 'fee_currency');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ const feeRate = this.safeFloat (feeInfo, 'fee_percentage');
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ 'rate': feeRate,
+ };
+ takerOrMaker = this.safeStringLower (feeInfo, 'fee_type');
+ }
+ return {
+ 'id': this.safeString2 (trade, 'trade_id', 'sequence'),
+ 'order': this.safeString (trade, 'order_id'),
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'type': undefined,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'takerOrMaker': takerOrMaker,
+ 'fee': fee,
+ 'info': trade,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'instrument_code': market['id'],
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()),
+ };
+ if (since !== undefined) {
+ // returns price ticks for a specific market with an interval of maximum of 4 hours
+ // sorted by latest first
+ request['from'] = this.iso8601 (since);
+ request['to'] = this.iso8601 (this.sum (since, 14400000));
+ }
+ const response = await this.publicGetPriceTicksInstrumentCode (this.extend (request, params));
+ //
+ // [
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "price":"8137.28",
+ // "amount":"0.22269",
+ // "taker_side":"BUY",
+ // "volume":"1812.0908832",
+ // "time":"2020-07-10T14:44:32.299Z",
+ // "trade_timestamp":1594392272299,
+ // "sequence":603047
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccountBalances (params);
+ //
+ // {
+ // "account_id":"4b95934f-55f1-460c-a525-bd5afc0cf071",
+ // "balances":[
+ // {
+ // "account_id":"4b95934f-55f1-460c-a525-bd5afc0cf071",
+ // "currency_code":"BTC",
+ // "change":"10.0",
+ // "available":"10.0",
+ // "locked":"0.0",
+ // "sequence":142135994,
+ // "time":"2020-07-01T10:57:32.959Z"
+ // }
+ // ]
+ // }
+ //
+ const balances = this.safeValue (response, 'balances', []);
+ const result = { 'info': response };
+ for (let i = 0; i < balances.length; i++) {
+ const balance = balances[i];
+ const currencyId = this.safeString (balance, 'currency_code');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['free'] = this.safeFloat (balance, 'available');
+ account['used'] = this.safeFloat (balance, 'locked');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ parseDepositAddress (depositAddress, currency = undefined) {
+ let code = undefined;
+ if (currency !== undefined) {
+ code = currency['code'];
+ }
+ const address = this.safeString (depositAddress, 'address');
+ const tag = this.safeString (depositAddress, 'destination_tag');
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': depositAddress,
+ };
+ }
+
+ async createDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privatePostAccountDepositCrypto (this.extend (request, params));
+ //
+ // {
+ // "address":"rBnNhk95FrdNisZtXcStzriFS8vEzz53DM",
+ // "destination_tag":"865690307",
+ // "enabled":true,
+ // "is_smart_contract":false
+ // }
+ //
+ return this.parseDepositAddress (response, currency);
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency_code': currency['id'],
+ };
+ const response = await this.privateGetAccountDepositCryptoCurrencyCode (this.extend (request, params));
+ //
+ // {
+ // "address":"rBnNhk95FrdNisZtXcStzriFS8vEzz53DM",
+ // "destination_tag":"865690307",
+ // "enabled":true,
+ // "is_smart_contract":false,
+ // "can_create_more":false
+ // }
+ //
+ return this.parseDepositAddress (response, currency);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'cursor': 'string', // pointer specifying the position from which the next pages should be returned
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency_code'] = currency['id'];
+ }
+ if (limit !== undefined) {
+ request['max_page_size'] = limit;
+ }
+ if (since !== undefined) {
+ const to = this.safeString (params, 'to');
+ if (to === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchDeposits requires a "to" iso8601 string param with the since argument is specified');
+ }
+ request['from'] = this.iso8601 (since);
+ }
+ const response = await this.privateGetAccountDeposits (this.extend (request, params));
+ //
+ // {
+ // "deposit_history": [
+ // {
+ // "transaction_id": "e5342efcd-d5b7-4a56-8e12-b69ffd68c5ef",
+ // "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
+ // "amount": "100",
+ // "type": "CRYPTO",
+ // "funds_source": "INTERNAL",
+ // "time": "2020-04-22T09:57:47Z",
+ // "currency": "BTC",
+ // "fee_amount": "0.0",
+ // "fee_currency": "BTC"
+ // },
+ // {
+ // "transaction_id": "79793d00-2899-4a4d-95b7-73ae6b31384f",
+ // "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
+ // "time": "2020-05-05T11:22:07.925Z",
+ // "currency": "EUR",
+ // "funds_source": "EXTERNAL",
+ // "type": "FIAT",
+ // "amount": "50.0",
+ // "fee_amount": "0.01",
+ // "fee_currency": "EUR"
+ // }
+ // ],
+ // "max_page_size": 2,
+ // "cursor": "eyJhY2NvdW50X2lkIjp7InMiOiJlMzY5YWM4MC00NTc3LTExZTktYWUwOC05YmVkYzQ3OTBiODQiLCJzcyI6W10sIm5zIjpbXSwiYnMiOltdLCJtIjp7fSwibCI6W119LCJpdGVtX2tleSI6eyJzIjoiV0lUSERSQVdBTDo6MmFlMjYwY2ItOTk3MC00YmNiLTgxNmEtZGY4MDVmY2VhZTY1Iiwic3MiOltdLCJucyI6W10sImJzIjpbXSwibSI6e30sImwiOltdfSwiZ2xvYmFsX3dpdGhkcmF3YWxfaW5kZXhfaGFzaF9rZXkiOnsicyI6ImUzNjlhYzgwLTQ1NzctMTFlOS1hZTA4LTliZWRjNDc5MGI4NCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX0sInRpbWVzdGFtcCI6eyJuIjoiMTU4ODA1ODc2Nzk0OCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX19"
+ // }
+ //
+ const depositHistory = this.safeValue (response, 'deposit_history', []);
+ return this.parseTransactions (depositHistory, currency, since, limit, { 'type': 'deposit' });
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'cursor': 'string', // pointer specifying the position from which the next pages should be returned
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency_code'] = currency['id'];
+ }
+ if (limit !== undefined) {
+ request['max_page_size'] = limit;
+ }
+ if (since !== undefined) {
+ const to = this.safeString (params, 'to');
+ if (to === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchWithdrawals requires a "to" iso8601 string param with the since argument is specified');
+ }
+ request['from'] = this.iso8601 (since);
+ }
+ const response = await this.privateGetAccountWithdrawals (this.extend (request, params));
+ //
+ // {
+ // "withdrawal_history": [
+ // {
+ // "account_id": "e369ac80-4577-11e9-ae08-9bedc4790b84",
+ // "amount": "0.1",
+ // "currency": "BTC",
+ // "fee_amount": "0.00002",
+ // "fee_currency": "BTC",
+ // "funds_source": "EXTERNAL",
+ // "related_transaction_id": "e298341a-3855-405e-bce3-92db368a3157",
+ // "time": "2020-05-05T11:11:32.110Z",
+ // "transaction_id": "6693ff40-bb10-4dcf-ada7-3b287727c882",
+ // "type": "CRYPTO"
+ // },
+ // {
+ // "account_id": "e369ac80-4577-11e9-ae08-9bedc4790b84",
+ // "amount": "0.1",
+ // "currency": "BTC",
+ // "fee_amount": "0.0",
+ // "fee_currency": "BTC",
+ // "funds_source": "INTERNAL",
+ // "time": "2020-05-05T10:29:53.464Z",
+ // "transaction_id": "ec9703b1-954b-4f76-adea-faac66eabc0b",
+ // "type": "CRYPTO"
+ // }
+ // ],
+ // "cursor": "eyJhY2NvdW50X2lkIjp7InMiOiJlMzY5YWM4MC00NTc3LTExZTktYWUwOC05YmVkYzQ3OTBiODQiLCJzcyI6W10sIm5zIjpbXSwiYnMiOltdLCJtIjp7fSwibCI6W119LCJpdGVtX2tleSI6eyJzIjoiV0lUSERSQVdBTDo6ZWM5NzAzYjEtOTU0Yi00Zjc2LWFkZWEtZmFhYzY2ZWFiYzBiIiwic3MiOltdLCJucyI6W10sImJzIjpbXSwibSI6e30sImwiOltdfSwiZ2xvYmFsX3dpdGhkcmF3YWxfaW5kZXhfaGFzaF9rZXkiOnsicyI6ImUzNjlhYzgwLTQ1NzctMTFlOS1hZTA4LTliZWRjNDc5MGI4NCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX0sInRpbWVzdGFtcCI6eyJuIjoiMTU4ODY3NDU5MzQ2NCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX19",
+ // "max_page_size": 2
+ // }
+ //
+ const withdrawalHistory = this.safeValue (response, 'withdrawal_history', []);
+ return this.parseTransactions (withdrawalHistory, currency, since, limit, { 'type': 'withdrawal' });
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': code,
+ 'amount': this.currencyToPrecision (code, amount),
+ // 'payout_account_id': '66756a10-3e86-48f4-9678-b634c4b135b2', // fiat only
+ // 'recipient': { // crypto only
+ // 'address': address,
+ // // 'destination_tag': '',
+ // },
+ };
+ const options = this.safeValue (this.options, 'fiat', []);
+ const isFiat = this.inArray (code, options);
+ const method = isFiat ? 'privatePostAccountWithdrawFiat' : 'privatePostAccountWithdrawCrypto';
+ if (isFiat) {
+ const payoutAccountId = this.safeString (params, 'payout_account_id');
+ if (payoutAccountId === undefined) {
+ throw ArgumentsRequired (this.id + ' withdraw() requires a payout_account_id param for fiat ' + code + ' withdrawals');
+ }
+ } else {
+ const recipient = { 'address': address };
+ if (tag !== undefined) {
+ recipient['destination_tag'] = tag;
+ }
+ request['recipient'] = recipient;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // crypto
+ //
+ // {
+ // "amount": "1234.5678",
+ // "fee": "1234.5678",
+ // "recipient": "3NacQ7rzZdhfyAtfJ5a11k8jFPdcMP2Bq7",
+ // "destination_tag": "",
+ // "transaction_id": "d0f8529f-f832-4e6a-9dc5-b8d5797badb2"
+ // }
+ //
+ // fiat
+ //
+ // {
+ // "transaction_id": "54236cd0-4413-11e9-93fb-5fea7e5b5df6"
+ // }
+ //
+ return this.parseTransaction (response, currency);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // fetchDeposits, fetchWithdrawals
+ //
+ // {
+ // "transaction_id": "C2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
+ // "type": "FIAT",
+ // "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
+ // "amount": "1234.5678",
+ // "time": "2019-08-24T14:15:22Z",
+ // "funds_source": "INTERNAL",
+ // "currency": "BTC",
+ // "fee_amount": "1234.5678",
+ // "fee_currency": "BTC",
+ // "blockchain_transaction_id": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
+ // "related_transaction_id": "e298341a-3855-405e-bce3-92db368a3157"
+ // }
+ //
+ // withdraw
+ //
+ //
+ // crypto
+ //
+ // {
+ // "amount": "1234.5678",
+ // "fee": "1234.5678",
+ // "recipient": "3NacQ7rzZdhfyAtfJ5a11k8jFPdcMP2Bq7",
+ // "destination_tag": "",
+ // "transaction_id": "d0f8529f-f832-4e6a-9dc5-b8d5797badb2"
+ // }
+ //
+ // fiat
+ //
+ // {
+ // "transaction_id": "54236cd0-4413-11e9-93fb-5fea7e5b5df6"
+ // }
+ //
+ const id = this.safeString (transaction, 'transaction_id');
+ const amount = this.safeFloat (transaction, 'amount');
+ const timestamp = this.parse8601 (this.safeString (transaction, 'time'));
+ const currencyId = this.safeString (transaction, 'currency');
+ currency = this.safeCurrency (currencyId, currency);
+ const status = 'ok'; // the exchange returns cleared transactions only
+ const feeCost = this.safeFloat2 (transaction, 'fee_amount', 'fee');
+ let fee = undefined;
+ const addressTo = this.safeString (transaction, 'recipient');
+ const tagTo = this.safeString (transaction, 'destination_tag');
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (transaction, 'fee_currency', currencyId);
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': currency['code'],
+ 'amount': amount,
+ 'address': addressTo,
+ 'addressFrom': undefined,
+ 'addressTo': addressTo,
+ 'tag': tagTo,
+ 'tagFrom': undefined,
+ 'tagTo': tagTo,
+ 'status': status,
+ 'type': undefined,
+ 'updated': undefined,
+ 'txid': this.safeString (transaction, 'blockchain_transaction_id'),
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': fee,
+ };
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'FILLED': 'open',
+ 'FILLED_FULLY': 'closed',
+ 'FILLED_CLOSED': 'canceled',
+ 'FILLED_REJECTED': 'rejected',
+ 'OPEN': 'open',
+ 'REJECTED': 'rejected',
+ 'CLOSED': 'canceled',
+ 'FAILED': 'failed',
+ 'STOP_TRIGGERED': 'triggered',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // "order_id": "d5492c24-2995-4c18-993a-5b8bf8fffc0d",
+ // "client_id": "d75fb03b-b599-49e9-b926-3f0b6d103206",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "instrument_code": "BTC_EUR",
+ // "time": "2019-08-01T08:00:44.026Z",
+ // "side": "BUY",
+ // "price": "5000",
+ // "amount": "1",
+ // "filled_amount": "0.5",
+ // "type": "LIMIT",
+ // "time_in_force": "GOOD_TILL_CANCELLED"
+ // }
+ //
+ // fetchOrder, fetchOpenOrders, fetchClosedOrders
+ //
+ // {
+ // "order": {
+ // "order_id": "66756a10-3e86-48f4-9678-b634c4b135b2",
+ // "account_id": "1eb2ad5d-55f1-40b5-bc92-7dc05869e905",
+ // "instrument_code": "BTC_EUR",
+ // "amount": "1234.5678",
+ // "filled_amount": "1234.5678",
+ // "side": "BUY",
+ // "type": "LIMIT",
+ // "status": "OPEN",
+ // "sequence": 123456789,
+ // "price": "1234.5678",
+ // "average_price": "1234.5678",
+ // "reason": "INSUFFICIENT_FUNDS",
+ // "time": "2019-08-24T14:15:22Z",
+ // "time_in_force": "GOOD_TILL_CANCELLED",
+ // "time_last_updated": "2019-08-24T14:15:22Z",
+ // "expire_after": "2019-08-24T14:15:22Z",
+ // "is_post_only": false,
+ // "time_triggered": "2019-08-24T14:15:22Z",
+ // "trigger_price": "1234.5678"
+ // },
+ // "trades": [
+ // {
+ // "fee": {
+ // "fee_amount": "0.0014",
+ // "fee_currency": "BTC",
+ // "fee_percentage": "0.1",
+ // "fee_group_id": "default",
+ // "fee_type": "TAKER",
+ // "running_trading_volume": "0.0"
+ // },
+ // "trade": {
+ // "trade_id": "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
+ // "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "amount": "1.4",
+ // "side": "BUY",
+ // "instrument_code": "BTC_EUR",
+ // "price": "7341.4",
+ // "time": "2019-09-27T15:05:32.564Z",
+ // "sequence": 48670
+ // }
+ // }
+ // ]
+ // }
+ //
+ const rawTrades = this.safeValue (order, 'trades', []);
+ order = this.safeValue (order, 'order', order);
+ const id = this.safeString (order, 'order_id');
+ const clientOrderId = this.safeString (order, 'client_id');
+ const timestamp = this.parse8601 (this.safeString (order, 'time'));
+ let status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const marketId = this.safeString (order, 'instrument_code');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'amount');
+ let cost = undefined;
+ const filled = this.safeFloat (order, 'filled_amount');
+ let remaining = undefined;
+ if (filled !== undefined) {
+ if (amount !== undefined) {
+ remaining = Math.max (0, amount - filled);
+ if (status === undefined) {
+ if (remaining > 0) {
+ status = 'open';
+ } else {
+ status = 'closed';
+ }
+ }
+ }
+ }
+ const side = this.safeStringLower (order, 'side');
+ const type = this.safeStringLower (order, 'type');
+ const trades = this.parseTrades (rawTrades, market, undefined, undefined);
+ const fees = [];
+ const numTrades = trades.length;
+ let lastTradeTimestamp = undefined;
+ let tradeCost = undefined;
+ let tradeAmount = undefined;
+ if (numTrades > 0) {
+ lastTradeTimestamp = trades[0]['timestamp'];
+ tradeCost = 0;
+ tradeAmount = 0;
+ for (let i = 0; i < trades.length; i++) {
+ const trade = trades[i];
+ fees.push (trade['fee']);
+ lastTradeTimestamp = Math.max (lastTradeTimestamp, trade['timestamp']);
+ tradeCost = this.sum (tradeCost, trade['cost']);
+ tradeAmount = this.sum (tradeAmount, trade['amount']);
+ }
+ }
+ let average = this.safeFloat (order, 'average_price');
+ if (average === undefined) {
+ if ((tradeCost !== undefined) && (tradeAmount !== undefined) && (tradeAmount !== 0)) {
+ average = tradeCost / tradeAmount;
+ }
+ }
+ if (cost === undefined) {
+ if ((average !== undefined) && (filled !== undefined)) {
+ cost = average * filled;
+ }
+ }
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'time_in_force'));
+ const stopPrice = this.safeFloat (order, 'trigger_price');
+ const result = {
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'info': order,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': timeInForce,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': stopPrice,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ // 'fee': undefined,
+ 'trades': trades,
+ };
+ const numFees = fees.length;
+ if (numFees > 0) {
+ if (numFees === 1) {
+ result['fee'] = fees[0];
+ } else {
+ const feesByCurrency = this.groupBy (fees, 'currency');
+ const feeCurrencies = Object.keys (feesByCurrency);
+ const numFeesByCurrency = feeCurrencies.length;
+ if (numFeesByCurrency === 1) {
+ const feeCurrency = feeCurrencies[0];
+ const feeArray = this.safeValue (feesByCurrency, feeCurrency);
+ let feeCost = 0;
+ for (let i = 0; i < feeArray.length; i++) {
+ feeCost = this.sum (feeCost, feeArray[i]['cost']);
+ }
+ result['fee'] = {
+ 'cost': feeCost,
+ 'currency': feeCurrency,
+ };
+ } else {
+ result['fees'] = fees;
+ }
+ }
+ } else {
+ result['fee'] = undefined;
+ }
+ return result;
+ }
+
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'GOOD_TILL_CANCELLED': 'GTC',
+ 'GOOD_TILL_TIME': 'GTT',
+ 'IMMEDIATE_OR_CANCELLED': 'IOC',
+ 'FILL_OR_KILL': 'FOK',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const uppercaseType = type.toUpperCase ();
+ const request = {
+ 'instrument_code': market['id'],
+ 'type': uppercaseType, // LIMIT, MARKET, STOP
+ 'side': side.toUpperCase (), // or SELL
+ 'amount': this.amountToPrecision (symbol, amount),
+ // "price": "1234.5678", // required for LIMIT and STOP orders
+ // "client_id": "d75fb03b-b599-49e9-b926-3f0b6d103206", // optional
+ // "time_in_force": "GOOD_TILL_CANCELLED", // limit orders only, GOOD_TILL_CANCELLED, GOOD_TILL_TIME, IMMEDIATE_OR_CANCELLED and FILL_OR_KILL
+ // "expire_after": "2020-07-02T19:40:13Z", // required for GOOD_TILL_TIME
+ // "is_post_only": false, // limit orders only, optional
+ // "trigger_price": "1234.5678" // required for stop orders
+ };
+ let priceIsRequired = false;
+ if (uppercaseType === 'LIMIT' || uppercaseType === 'STOP') {
+ priceIsRequired = true;
+ }
+ if (uppercaseType === 'STOP') {
+ const triggerPrice = this.safeFloat (params, 'trigger_price');
+ if (triggerPrice === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder requires a trigger_price param for ' + type + ' orders');
+ }
+ request['trigger_price'] = this.priceToPrecision (symbol, triggerPrice);
+ params = this.omit (params, 'trigger_price');
+ }
+ if (priceIsRequired) {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_id');
+ if (clientOrderId !== undefined) {
+ request['client_id'] = clientOrderId;
+ params = this.omit (params, [ 'clientOrderId', 'client_id' ]);
+ }
+ const response = await this.privatePostAccountOrders (this.extend (request, params));
+ //
+ // {
+ // "order_id": "d5492c24-2995-4c18-993a-5b8bf8fffc0d",
+ // "client_id": "d75fb03b-b599-49e9-b926-3f0b6d103206",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "instrument_code": "BTC_EUR",
+ // "time": "2019-08-01T08:00:44.026Z",
+ // "side": "BUY",
+ // "price": "5000",
+ // "amount": "1",
+ // "filled_amount": "0.5",
+ // "type": "LIMIT",
+ // "time_in_force": "GOOD_TILL_CANCELLED"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_id');
+ params = this.omit (params, [ 'clientOrderId', 'client_id' ]);
+ let method = 'privateDeleteAccountOrdersOrderId';
+ const request = {};
+ if (clientOrderId !== undefined) {
+ method = 'privateDeleteAccountOrdersClientClientId';
+ request['client_id'] = clientOrderId;
+ } else {
+ request['order_id'] = id;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // responds with an empty body
+ //
+ return response;
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ if (symbol !== undefined) {
+ const market = this.market (symbol);
+ request['instrument_code'] = market['id'];
+ }
+ const response = await this.privateDeleteAccountOrders (this.extend (request, params));
+ //
+ // [
+ // "a10e9bd1-8f72-4cfe-9f1b-7f1c8a9bd8ee"
+ // ]
+ //
+ return response;
+ }
+
+ async cancelOrders (ids, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'ids': ids.join (','),
+ };
+ const response = await this.privateDeleteAccountOrders (this.extend (request, params));
+ //
+ // [
+ // "a10e9bd1-8f72-4cfe-9f1b-7f1c8a9bd8ee"
+ // ]
+ //
+ return response;
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'order_id': id,
+ };
+ const response = await this.privateGetAccountOrdersOrderId (this.extend (request, params));
+ //
+ // {
+ // "order": {
+ // "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "time_last_updated": "2019-09-27T15:05:35.096Z",
+ // "sequence": 48782,
+ // "price": "7349.2",
+ // "filled_amount": "100.0",
+ // "status": "FILLED_FULLY",
+ // "amount": "100.0",
+ // "instrument_code": "BTC_EUR",
+ // "side": "BUY",
+ // "time": "2019-09-27T15:05:32.063Z",
+ // "type": "MARKET"
+ // },
+ // "trades": [
+ // {
+ // "fee": {
+ // "fee_amount": "0.0014",
+ // "fee_currency": "BTC",
+ // "fee_percentage": "0.1",
+ // "fee_group_id": "default",
+ // "fee_type": "TAKER",
+ // "running_trading_volume": "0.0"
+ // },
+ // "trade": {
+ // "trade_id": "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
+ // "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "amount": "1.4",
+ // "side": "BUY",
+ // "instrument_code": "BTC_EUR",
+ // "price": "7341.4",
+ // "time": "2019-09-27T15:05:32.564Z",
+ // "sequence": 48670
+ // }
+ // }
+ // ]
+ // }
+ //
+ return this.parseOrder (response);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()), // max range is 100 days
+ // 'instrument_code': market['id'],
+ // 'with_cancelled_and_rejected': false, // default is false, orders which have been cancelled by the user before being filled or rejected by the system as invalid, additionally, all inactive filled orders which would return with "with_just_filled_inactive"
+ // 'with_just_filled_inactive': false, // orders which have been filled and are no longer open, use of "with_cancelled_and_rejected" extends "with_just_filled_inactive" and in case both are specified the latter is ignored
+ // 'with_just_orders': false, // do not return any trades corresponsing to the orders, it may be significanly faster and should be used if user is not interesting in trade information
+ // 'max_page_size': 100,
+ // 'cursor': 'string', // pointer specifying the position from which the next pages should be returned
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['instrument_code'] = market['id'];
+ }
+ if (since !== undefined) {
+ const to = this.safeString (params, 'to');
+ if (to === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrders requires a "to" iso8601 string param with the since argument is specified, max range is 100 days');
+ }
+ request['from'] = this.iso8601 (since);
+ }
+ if (limit !== undefined) {
+ request['max_page_size'] = limit;
+ }
+ const response = await this.privateGetAccountOrders (this.extend (request, params));
+ //
+ // {
+ // "order_history": [
+ // {
+ // "order": {
+ // "trigger_price": "12089.88",
+ // "order_id": "d453ca12-c650-46dd-9dee-66910d96bfc0",
+ // "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
+ // "instrument_code": "BTC_USDT",
+ // "time": "2019-08-23T10:02:31.663Z",
+ // "side": "SELL",
+ // "price": "10159.76",
+ // "average_price": "10159.76",
+ // "amount": "0.2",
+ // "filled_amount": "0.2",
+ // "type": "STOP",
+ // "sequence": 8,
+ // "status": "FILLED_FULLY"
+ // },
+ // "trades": [
+ // {
+ // "fee": {
+ // "fee_amount": "0.4188869",
+ // "fee_currency": "USDT",
+ // "fee_percentage": "0.1",
+ // "fee_group_id": "default",
+ // "fee_type": "TAKER",
+ // "running_trading_volume": "0.0"
+ // },
+ // "trade": {
+ // "trade_id": "ec82896f-fd1b-4cbb-89df-a9da85ccbb4b",
+ // "order_id": "d453ca12-c650-46dd-9dee-66910d96bfc0",
+ // "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
+ // "amount": "0.2",
+ // "side": "SELL",
+ // "instrument_code": "BTC_USDT",
+ // "price": "10159.76",
+ // "time": "2019-08-23T10:02:32.663Z",
+ // "sequence": 9
+ // }
+ // }
+ // ]
+ // },
+ // {
+ // "order": {
+ // "order_id": "5151a99e-f414-418f-8cf1-2568d0a63ea5",
+ // "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
+ // "instrument_code": "BTC_USDT",
+ // "time": "2019-08-23T10:01:36.773Z",
+ // "side": "SELL",
+ // "price": "12289.88",
+ // "amount": "0.5",
+ // "filled_amount": "0.0",
+ // "type": "LIMIT",
+ // "sequence": 7,
+ // "status": "OPEN"
+ // },
+ // "trades": []
+ // },
+ // {
+ // "order": {
+ // "order_id": "ac80d857-75e1-4733-9070-fd4288395fdc",
+ // "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
+ // "instrument_code": "BTC_USDT",
+ // "time": "2019-08-23T10:01:25.031Z",
+ // "side": "SELL",
+ // "price": "11089.88",
+ // "amount": "0.1",
+ // "filled_amount": "0.0",
+ // "type": "LIMIT",
+ // "sequence": 6,
+ // "status": "OPEN"
+ // },
+ // "trades": []
+ // }
+ // ],
+ // "max_page_size": 100
+ // }
+ //
+ const orderHistory = this.safeValue (response, 'order_history', []);
+ return this.parseOrders (orderHistory, market, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'with_cancelled_and_rejected': true, // default is false, orders which have been cancelled by the user before being filled or rejected by the system as invalid, additionally, all inactive filled orders which would return with "with_just_filled_inactive"
+ };
+ return await this.fetchOpenOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'order_id': id,
+ // 'max_page_size': 100,
+ // 'cursor': 'string', // pointer specifying the position from which the next pages should be returned
+ };
+ if (limit !== undefined) {
+ request['max_page_size'] = limit;
+ }
+ const response = await this.privateGetAccountOrdersOrderIdTrades (this.extend (request, params));
+ //
+ // {
+ // "trade_history": [
+ // {
+ // "trade": {
+ // "trade_id": "2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
+ // "order_id": "66756a10-3e86-48f4-9678-b634c4b135b2",
+ // "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
+ // "amount": "1234.5678",
+ // "side": "BUY",
+ // "instrument_code": "BTC_EUR",
+ // "price": "1234.5678",
+ // "time": "2019-08-24T14:15:22Z",
+ // "price_tick_sequence": 0,
+ // "sequence": 123456789
+ // },
+ // "fee": {
+ // "fee_amount": "1234.5678",
+ // "fee_percentage": "1234.5678",
+ // "fee_group_id": "default",
+ // "running_trading_volume": "1234.5678",
+ // "fee_currency": "BTC",
+ // "fee_type": "TAKER"
+ // }
+ // }
+ // ],
+ // "max_page_size": 0,
+ // "cursor": "string"
+ // }
+ //
+ const tradeHistory = this.safeValue (response, 'trade_history', []);
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ return this.parseTrades (tradeHistory, market, since, limit);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()), // max range is 100 days
+ // 'instrument_code': market['id'],
+ // 'max_page_size': 100,
+ // 'cursor': 'string', // pointer specifying the position from which the next pages should be returned
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['instrument_code'] = market['id'];
+ }
+ if (since !== undefined) {
+ const to = this.safeString (params, 'to');
+ if (to === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a "to" iso8601 string param with the since argument is specified, max range is 100 days');
+ }
+ request['from'] = this.iso8601 (since);
+ }
+ if (limit !== undefined) {
+ request['max_page_size'] = limit;
+ }
+ const response = await this.privateGetAccountTrades (this.extend (request, params));
+ //
+ // {
+ // "trade_history": [
+ // {
+ // "trade": {
+ // "trade_id": "2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
+ // "order_id": "66756a10-3e86-48f4-9678-b634c4b135b2",
+ // "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
+ // "amount": "1234.5678",
+ // "side": "BUY",
+ // "instrument_code": "BTC_EUR",
+ // "price": "1234.5678",
+ // "time": "2019-08-24T14:15:22Z",
+ // "price_tick_sequence": 0,
+ // "sequence": 123456789
+ // },
+ // "fee": {
+ // "fee_amount": "1234.5678",
+ // "fee_percentage": "1234.5678",
+ // "fee_group_id": "default",
+ // "running_trading_volume": "1234.5678",
+ // "fee_currency": "BTC",
+ // "fee_type": "TAKER"
+ // }
+ // }
+ // ],
+ // "max_page_size": 0,
+ // "cursor": "string"
+ // }
+ //
+ const tradeHistory = this.safeValue (response, 'trade_history', []);
+ return this.parseTrades (tradeHistory, market, since, limit);
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let url = this.urls['api'][api] + '/' + this.version + '/' + this.implodeParams (path, params);
+ const query = this.omit (params, this.extractParams (path));
+ if (api === 'public') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (api === 'private') {
+ this.checkRequiredCredentials ();
+ headers = {
+ 'Accept': 'application/json',
+ 'Authorization': 'Bearer ' + this.apiKey,
+ };
+ if (method === 'POST') {
+ body = this.json (query);
+ headers['Content-Type'] = 'application/json';
+ } else {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return;
+ }
+ //
+ // {"error":"MISSING_FROM_PARAM"}
+ // {"error":"MISSING_TO_PARAM"}
+ // {"error":"CANDLESTICKS_TIME_RANGE_TOO_BIG"}
+ //
+ const message = this.safeString (response, 'error');
+ if (message !== undefined) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7}],40:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { ExchangeError, InvalidNonce, AuthenticationError, OrderNotFound } = require ('./base/errors');
+const { TICK_SIZE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -21367,26 +28146,37 @@ module.exports = class bitso extends Exchange {
'rateLimit': 2000, // 30 requests per minute
'version': 'v3',
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchDepositAddress': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27766335-715ce7aa-5ed5-11e7-88a8-173a27bb30fe.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295554-11f98280-c50e-11ea-80d6-15b3bafa8cbf.jpg',
'api': 'https://api.bitso.com',
'www': 'https://bitso.com',
'doc': 'https://bitso.com/api_info',
- 'fees': 'https://bitso.com/fees?l=es',
+ 'fees': 'https://bitso.com/fees',
'referral': 'https://bitso.com/?ref=itej',
},
+ 'precisionMode': TICK_SIZE,
'options': {
'precision': {
- 'XRP': 6,
- 'MXN': 2,
- 'TUSD': 2,
+ 'XRP': 0.000001,
+ 'MXN': 0.01,
+ 'TUSD': 0.01,
},
- 'defaultPrecision': 8,
+ 'defaultPrecision': 0.00000001,
},
'api': {
'public': {
@@ -21451,6 +28241,38 @@ module.exports = class bitso extends Exchange {
async fetchMarkets (params = {}) {
const response = await this.publicGetAvailableBooks (params);
+ //
+ // {
+ // "success":true,
+ // "payload":[
+ // {
+ // "book":"btc_mxn",
+ // "minimum_price":"500",
+ // "maximum_price":"10000000",
+ // "minimum_amount":"0.00005",
+ // "maximum_amount":"500",
+ // "minimum_value":"5",
+ // "maximum_value":"10000000",
+ // "tick_size":"0.01",
+ // "fees":{
+ // "flat_rate":{"maker":"0.500","taker":"0.650"},
+ // "structure":[
+ // {"volume":"1500000","maker":"0.00500","taker":"0.00650"},
+ // {"volume":"2000000","maker":"0.00490","taker":"0.00637"},
+ // {"volume":"5000000","maker":"0.00480","taker":"0.00624"},
+ // {"volume":"7000000","maker":"0.00440","taker":"0.00572"},
+ // {"volume":"10000000","maker":"0.00420","taker":"0.00546"},
+ // {"volume":"15000000","maker":"0.00400","taker":"0.00520"},
+ // {"volume":"35000000","maker":"0.00370","taker":"0.00481"},
+ // {"volume":"50000000","maker":"0.00300","taker":"0.00390"},
+ // {"volume":"150000000","maker":"0.00200","taker":"0.00260"},
+ // {"volume":"250000000","maker":"0.00100","taker":"0.00130"},
+ // {"volume":"9999999999","maker":"0.00000","taker":"0.00130"},
+ // ]
+ // }
+ // },
+ // ]
+ // }
const markets = this.safeValue (response, 'payload');
const result = [];
for (let i = 0; i < markets.length; i++) {
@@ -21476,11 +28298,43 @@ module.exports = class bitso extends Exchange {
'max': this.safeFloat (market, 'maximum_value'),
},
};
+ const defaultPricePrecision = this.safeFloat (this.options['precision'], quote, this.options['defaultPrecision']);
+ const pricePrecision = this.safeFloat (market, 'tick_size', defaultPricePrecision);
const precision = {
- 'amount': this.safeInteger (this.options['precision'], base, this.options['defaultPrecision']),
- 'price': this.safeInteger (this.options['precision'], quote, this.options['defaultPrecision']),
+ 'amount': this.safeFloat (this.options['precision'], base, this.options['defaultPrecision']),
+ 'price': pricePrecision,
};
- result.push ({
+ const fees = this.safeValue (market, 'fees', {});
+ const flatRate = this.safeValue (fees, 'flat_rate', {});
+ const maker = this.safeFloat (flatRate, 'maker');
+ const taker = this.safeFloat (flatRate, 'taker');
+ const feeTiers = this.safeValue (fees, 'structure', []);
+ const fee = {
+ 'maker': maker,
+ 'taker': taker,
+ 'percentage': true,
+ 'tierBased': true,
+ };
+ const takerFees = [];
+ const makerFees = [];
+ for (let i = 0; i < feeTiers.length; i++) {
+ const tier = feeTiers[i];
+ const volume = this.safeFloat (tier, 'volume');
+ const takerFee = this.safeFloat (tier, 'taker');
+ const makerFee = this.safeFloat (tier, 'maker');
+ takerFees.push ([ volume, takerFee ]);
+ makerFees.push ([ volume, makerFee ]);
+ if (i === 0) {
+ fee['taker'] = taker;
+ fee['maker'] = maker;
+ }
+ }
+ const tiers = {
+ 'taker': takerFees,
+ 'maker': makerFees,
+ };
+ fee['tiers'] = tiers;
+ result.push (this.extend ({
'id': id,
'symbol': symbol,
'base': base,
@@ -21491,7 +28345,7 @@ module.exports = class bitso extends Exchange {
'limits': limits,
'precision': precision,
'active': undefined,
- });
+ }, fee));
}
return result;
}
@@ -21567,16 +28421,8 @@ module.exports = class bitso extends Exchange {
parseTrade (trade, market = undefined) {
const timestamp = this.parse8601 (this.safeString (trade, 'created_at'));
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (trade, 'book');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (trade, 'book');
+ const symbol = this.safeSymbol (marketId, market, '_');
const side = this.safeString2 (trade, 'side', 'maker_side');
let amount = this.safeFloat2 (trade, 'amount', 'major');
if (amount !== undefined) {
@@ -21693,23 +28539,8 @@ module.exports = class bitso extends Exchange {
const id = this.safeString (order, 'oid');
const side = this.safeString (order, 'side');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let symbol = undefined;
const marketId = this.safeString (order, 'book');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const orderType = this.safeString (order, 'type');
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const price = this.safeFloat (order, 'price');
@@ -21731,8 +28562,10 @@ module.exports = class bitso extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': orderType,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': undefined,
'remaining': remaining,
@@ -21807,10 +28640,10 @@ module.exports = class bitso extends Exchange {
const response = await this.privateGetFundingDestination (this.extend (request, params));
let address = this.safeString (response['payload'], 'account_identifier');
let tag = undefined;
- if (code === 'XRP') {
+ if (address.indexOf ('?dt=') >= 0) {
const parts = address.split ('?dt=');
- address = parts[0];
- tag = parts[1];
+ address = this.safeString (parts, 0);
+ tag = this.safeString (parts, 1);
}
this.checkAddress (address);
return {
@@ -21917,13 +28750,13 @@ module.exports = class bitso extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],41:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],41:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { AuthenticationError, ExchangeError, NotSupported, PermissionDenied, InvalidNonce, OrderNotFound, InsufficientFunds, InvalidAddress, InvalidOrder } = require ('./base/errors');
+const { AuthenticationError, ExchangeError, NotSupported, PermissionDenied, InvalidNonce, OrderNotFound, InsufficientFunds, InvalidAddress, InvalidOrder, ArgumentsRequired, OnMaintenance } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -21939,13 +28772,27 @@ module.exports = class bitstamp extends Exchange {
'pro': true,
'has': {
'CORS': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchDepositAddress': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
+ 'fetchMarkets': true,
+ 'fetchCurrencies': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
'fetchTransactions': true,
'fetchWithdrawals': true,
'withdraw': true,
+ 'fetchTradingFee': true,
+ 'fetchTradingFees': true,
+ 'fetchFundingFees': true,
+ 'fetchFees': true,
+ 'fetchLedger': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27786377-8c8ab57e-5fe9-11e7-8ea4-2b05b6bcceec.jpg',
@@ -21957,6 +28804,20 @@ module.exports = class bitstamp extends Exchange {
'www': 'https://www.bitstamp.net',
'doc': 'https://www.bitstamp.net/api',
},
+ 'timeframes': {
+ '1m': '60',
+ '3m': '180',
+ '5m': '300',
+ '15m': '900',
+ '30m': '1800',
+ '1h': '3600',
+ '2h': '7200',
+ '4h': '14400',
+ '6h': '21600',
+ '12h': '43200',
+ '1d': '86400',
+ '1w': '259200',
+ },
'requiredCredentials': {
'apiKey': true,
'secret': true,
@@ -21965,6 +28826,7 @@ module.exports = class bitstamp extends Exchange {
'api': {
'public': {
'get': [
+ 'ohlc/{pair}/',
'order_book/{pair}/',
'ticker_hour/{pair}/',
'ticker/{pair}/',
@@ -21996,6 +28858,16 @@ module.exports = class bitstamp extends Exchange {
'eth_address/',
'xrp_withdrawal/',
'xrp_address/',
+ 'xlm_withdrawal/',
+ 'xlm_address/',
+ 'pax_withdrawal/',
+ 'pax_address/',
+ 'link_withdrawal/',
+ 'link_address/',
+ 'usdc_withdrawal/',
+ 'usdc_address/',
+ 'omg_withdrawal/',
+ 'omg_address/',
'transfer-to-main/',
'transfer-from-main/',
'withdrawal-requests/',
@@ -22034,7 +28906,13 @@ module.exports = class bitstamp extends Exchange {
[2000000, 0.13 / 100],
[4000000, 0.12 / 100],
[20000000, 0.11 / 100],
- [20000001, 0.10 / 100],
+ [50000000, 0.10 / 100],
+ [100000000, 0.07 / 100],
+ [500000000, 0.05 / 100],
+ [2000000000, 0.03 / 100],
+ [6000000000, 0.01 / 100],
+ [10000000000, 0.005 / 100],
+ [10000000001, 0.0],
],
'maker': [
[0, 0.5 / 100],
@@ -22047,7 +28925,13 @@ module.exports = class bitstamp extends Exchange {
[2000000, 0.13 / 100],
[4000000, 0.12 / 100],
[20000000, 0.11 / 100],
- [20000001, 0.10 / 100],
+ [50000000, 0.10 / 100],
+ [100000000, 0.07 / 100],
+ [500000000, 0.05 / 100],
+ [2000000000, 0.03 / 100],
+ [6000000000, 0.01 / 100],
+ [10000000000, 0.005 / 100],
+ [10000000001, 0.0],
],
},
},
@@ -22055,13 +28939,15 @@ module.exports = class bitstamp extends Exchange {
'tierBased': false,
'percentage': false,
'withdraw': {
- 'BTC': 0,
- 'BCH': 0,
- 'LTC': 0,
- 'ETH': 0,
- 'XRP': 0,
+ 'BTC': 0.0005,
+ 'BCH': 0.0001,
+ 'LTC': 0.001,
+ 'ETH': 0.001,
+ 'XRP': 0.02,
+ 'XLM': 0.005,
+ 'PAX': 0.5,
'USD': 25,
- 'EUR': 0.90,
+ 'EUR': 3.0,
},
'deposit': {
'BTC': 0,
@@ -22069,7 +28955,9 @@ module.exports = class bitstamp extends Exchange {
'LTC': 0,
'ETH': 0,
'XRP': 0,
- 'USD': 25,
+ 'XLM': 0,
+ 'PAX': 0,
+ 'USD': 7.5,
'EUR': 0,
},
},
@@ -22087,6 +28975,7 @@ module.exports = class bitstamp extends Exchange {
'Please update your profile with your FATCA information, before using API.': PermissionDenied,
'Order not found': OrderNotFound,
'Price is more than 20% below market price.': InvalidOrder,
+ 'Bitstamp.net is under scheduled maintenance.': OnMaintenance, // { "error": "Bitstamp.net is under scheduled maintenance. We'll be back soon." }
},
'broad': {
'Minimum order size is': InvalidOrder, // Minimum order size is 5.0 EUR.
@@ -22098,7 +28987,7 @@ module.exports = class bitstamp extends Exchange {
}
async fetchMarkets (params = {}) {
- const response = await this.publicGetTradingPairsInfo (params);
+ const response = await this.fetchMarketsFromCache (params);
const result = [];
for (let i = 0; i < response.length; i++) {
const market = response[i];
@@ -22149,6 +29038,84 @@ module.exports = class bitstamp extends Exchange {
return result;
}
+ constructCurrencyObject (id, code, name, precision, minCost, originalPayload) {
+ let currencyType = 'crypto';
+ const description = this.describe ();
+ if (this.isFiat (code)) {
+ currencyType = 'fiat';
+ }
+ return {
+ 'id': id,
+ 'code': code,
+ 'info': originalPayload, // the original payload
+ 'type': currencyType,
+ 'name': name,
+ 'active': true,
+ 'fee': this.safeFloat (description['fees']['funding']['withdraw'], code),
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': Math.pow (10, -precision),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': Math.pow (10, -precision),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': minCost,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ };
+ }
+
+ async fetchMarketsFromCache (params = {}) {
+ // this method is now redundant
+ // currencies are now fetched before markets
+ const options = this.safeValue (this.options, 'fetchMarkets', {});
+ const timestamp = this.safeInteger (options, 'timestamp');
+ const expires = this.safeInteger (options, 'expires', 1000);
+ const now = this.milliseconds ();
+ if ((timestamp === undefined) || ((now - timestamp) > expires)) {
+ const response = await this.publicGetTradingPairsInfo (params);
+ this.options['fetchMarkets'] = this.extend (options, {
+ 'response': response,
+ 'timestamp': now,
+ });
+ }
+ return this.safeValue (this.options['fetchMarkets'], 'response');
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.fetchMarketsFromCache (params);
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ const name = this.safeString (market, 'name');
+ let [ base, quote ] = name.split ('/');
+ const baseId = base.toLowerCase ();
+ const quoteId = quote.toLowerCase ();
+ base = this.safeCurrencyCode (base);
+ quote = this.safeCurrencyCode (quote);
+ const description = this.safeString (market, 'description');
+ const [ baseDescription, quoteDescription ] = description.split (' / ');
+ const parts = market['minimum_order'].split (' ');
+ const cost = parts[0];
+ if (!(base in result)) {
+ result[base] = this.constructCurrencyObject (baseId, base, baseDescription, market['base_decimals'], undefined, market);
+ }
+ if (!(quote in result)) {
+ result[quote] = this.constructCurrencyObject (quoteId, quote, quoteDescription, market['counter_decimals'], parseFloat (cost), market);
+ }
+ }
+ return result;
+ }
+
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {
@@ -22421,6 +29388,16 @@ module.exports = class bitstamp extends Exchange {
};
}
+ parseTradingFee (balances, symbol) {
+ const market = this.market (symbol);
+ const tradeFee = this.safeFloat (balances, market['id'] + '_fee');
+ return {
+ 'symbol': symbol,
+ 'maker': tradeFee,
+ 'taker': tradeFee,
+ };
+ }
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -22450,6 +29427,71 @@ module.exports = class bitstamp extends Exchange {
return this.parseTrades (response, market, since, limit);
}
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "high": "9064.77",
+ // "timestamp": "1593961440",
+ // "volume": "18.49436608",
+ // "low": "9040.87",
+ // "close": "9064.77",
+ // "open": "9040.87"
+ // }
+ //
+ return [
+ this.safeTimestamp (ohlcv, 'timestamp'),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'volume'),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'pair': market['id'],
+ 'step': this.timeframes[timeframe],
+ };
+ const duration = this.parseTimeframe (timeframe);
+ if (limit === undefined) {
+ if (since === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument');
+ } else {
+ limit = 1000;
+ const start = parseInt (since / 1000);
+ request['start'] = start;
+ request['end'] = this.sum (start, limit * duration);
+ request['limit'] = limit;
+ }
+ } else {
+ if (since !== undefined) {
+ const start = parseInt (since / 1000);
+ request['start'] = start;
+ request['end'] = this.sum (start, limit * duration);
+ }
+ request['limit'] = Math.min (limit, 1000); // min 1, max 1000
+ }
+ const response = await this.publicGetOhlcPair (this.extend (request, params));
+ //
+ // {
+ // "data": {
+ // "pair": "BTC/USD",
+ // "ohlc": [
+ // {"high": "9064.77", "timestamp": "1593961440", "volume": "18.49436608", "low": "9040.87", "close": "9064.77", "open": "9040.87"},
+ // {"high": "9071.59", "timestamp": "1593961500", "volume": "3.48631711", "low": "9058.76", "close": "9061.07", "open": "9064.66"},
+ // {"high": "9067.33", "timestamp": "1593961560", "volume": "0.04142833", "low": "9061.94", "close": "9061.94", "open": "9067.33"},
+ // ],
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const ohlc = this.safeValue (data, 'ohlc', []);
+ return this.parseOHLCVs (ohlc, market, timeframe, since, limit);
+ }
+
async fetchBalance (params = {}) {
await this.loadMarkets ();
const balance = await this.privatePostBalance (params);
@@ -22468,6 +29510,80 @@ module.exports = class bitstamp extends Exchange {
return this.parseBalance (result);
}
+ async fetchTradingFee (symbol, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let method = 'privatePostBalance';
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['pair'] = market['id'];
+ method += 'Pair';
+ }
+ const balance = await this[method] (this.extend (request, params));
+ return {
+ 'info': balance,
+ 'symbol': symbol,
+ 'maker': balance.fee,
+ 'taker': balance.fee,
+ };
+ }
+
+ praseTradingFees (balance) {
+ const result = { 'info': balance };
+ const markets = Object.keys (this.markets);
+ for (let i = 0; i < markets.length; i++) {
+ const symbol = markets[i];
+ const fee = this.parseTradingFee (balance, symbol);
+ result[symbol] = fee;
+ }
+ return result;
+ }
+
+ async fetchTradingFees (params = {}) {
+ await this.loadMarkets ();
+ const balance = await this.privatePostBalance (params);
+ return this.praseTradingFees (balance);
+ }
+
+ parseFundingFees (balance) {
+ const withdraw = {};
+ const ids = Object.keys (balance);
+ for (let i = 0; i < ids.length; i++) {
+ const id = ids[i];
+ if (id.indexOf ('_withdrawal_fee') >= 0) {
+ const currencyId = id.split ('_')[0];
+ const code = this.safeCurrencyCode (currencyId);
+ withdraw[code] = this.safeFloat (balance, id);
+ }
+ }
+ return {
+ 'info': balance,
+ 'withdraw': withdraw,
+ 'deposit': {},
+ };
+ }
+
+ async fetchFundingFees (params = {}) {
+ await this.loadMarkets ();
+ const balance = await this.privatePostBalance (params);
+ return this.parseFundingFees (balance);
+ }
+
+ async fetchFees (params = {}) {
+ await this.loadMarkets ();
+ const balance = await this.privatePostBalance (params);
+ const tradingFees = this.praseTradingFees (balance);
+ delete tradingFees['info'];
+ const fundingFees = this.parseFundingFees (balance);
+ delete fundingFees['info'];
+ return {
+ 'info': balance,
+ 'trading': tradingFees,
+ 'funding': fundingFees,
+ };
+ }
+
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -22478,6 +29594,8 @@ module.exports = class bitstamp extends Exchange {
};
if (type === 'market') {
method += 'Market';
+ } else if (type === 'instant') {
+ method += 'Instant';
} else {
request['price'] = this.priceToPrecision (symbol, price);
}
@@ -22607,6 +29725,8 @@ module.exports = class bitstamp extends Exchange {
const request = {};
if (since !== undefined) {
request['timedelta'] = this.milliseconds () - since;
+ } else {
+ request['timedelta'] = 50000000; // use max bitstamp approved value
}
const response = await this.privatePostWithdrawalRequests (this.extend (request, params));
//
@@ -22894,8 +30014,10 @@ module.exports = class bitstamp extends Exchange {
'status': status,
'symbol': symbol,
'type': undefined,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -22907,6 +30029,124 @@ module.exports = class bitstamp extends Exchange {
};
}
+ parseLedgerEntryType (type) {
+ const types = {
+ '0': 'transaction',
+ '1': 'transaction',
+ '2': 'trade',
+ '14': 'transfer',
+ };
+ return this.safeString (types, type, type);
+ }
+
+ parseLedgerEntry (item, currency = undefined) {
+ //
+ // [
+ // {
+ // "fee": "0.00000000",
+ // "btc_usd": "0.00",
+ // "id": 1234567894,
+ // "usd": 0,
+ // "btc": 0,
+ // "datetime": "2018-09-08 09:00:31",
+ // "type": "1",
+ // "xrp": "-20.00000000",
+ // "eur": 0,
+ // },
+ // {
+ // "fee": "0.00000000",
+ // "btc_usd": "0.00",
+ // "id": 1134567891,
+ // "usd": 0,
+ // "btc": 0,
+ // "datetime": "2018-09-07 18:47:52",
+ // "type": "0",
+ // "xrp": "20.00000000",
+ // "eur": 0,
+ // },
+ // ]
+ //
+ const type = this.parseLedgerEntryType (this.safeString (item, 'type'));
+ if (type === 'trade') {
+ const parsedTrade = this.parseTrade (item);
+ let market = undefined;
+ const keys = Object.keys (item);
+ for (let i = 0; i < keys.length; i++) {
+ if (keys[i].indexOf ('_') >= 0) {
+ const marketId = keys[i].replace ('_', '');
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ }
+ }
+ }
+ // if the market is still not defined
+ // try to deduce it from used keys
+ if (market === undefined) {
+ market = this.getMarketFromTrade (item);
+ }
+ const direction = parsedTrade['side'] === 'buy' ? 'in' : 'out';
+ return {
+ 'id': parsedTrade['id'],
+ 'info': item,
+ 'timestamp': parsedTrade['timestamp'],
+ 'datetime': parsedTrade['datetime'],
+ 'direction': direction,
+ 'account': undefined,
+ 'referenceId': parsedTrade['order'],
+ 'referenceAccount': undefined,
+ 'type': type,
+ 'currency': market['base'],
+ 'amount': parsedTrade['amount'],
+ 'before': undefined,
+ 'after': undefined,
+ 'status': 'ok',
+ 'fee': parsedTrade['fee'],
+ };
+ } else {
+ const parsedTransaction = this.parseTransaction (item);
+ let direction = undefined;
+ if ('amount' in item) {
+ const amount = this.safeFloat (item, 'amount');
+ direction = amount > 0 ? 'in' : 'out';
+ } else if (('currency' in parsedTransaction) && parsedTransaction['currency'] !== undefined) {
+ const currencyId = this.currencyId (parsedTransaction['currency']);
+ const amount = this.safeFloat (item, currencyId);
+ direction = amount > 0 ? 'in' : 'out';
+ }
+ return {
+ 'id': parsedTransaction['id'],
+ 'info': item,
+ 'timestamp': parsedTransaction['timestamp'],
+ 'datetime': parsedTransaction['datetime'],
+ 'direction': direction,
+ 'account': undefined,
+ 'referenceId': parsedTransaction['txid'],
+ 'referenceAccount': undefined,
+ 'type': type,
+ 'currency': parsedTransaction['currency'],
+ 'amount': parsedTransaction['amount'],
+ 'before': undefined,
+ 'after': undefined,
+ 'status': parsedTransaction['status'],
+ 'fee': parsedTransaction['fee'],
+ };
+ }
+ }
+
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privatePostUserTransactions (this.extend (request, params));
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ return this.parseLedger (response, currency, since, limit);
+ }
+
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
let market = undefined;
await this.loadMarkets ();
@@ -22925,18 +30165,10 @@ module.exports = class bitstamp extends Exchange {
// }
// ]
//
- const result = [];
- for (let i = 0; i < response.length; i++) {
- const order = this.parseOrder (response[i], market);
- result.push (this.extend (order, {
- 'status': 'open',
- 'type': 'limit',
- }));
- }
- if (symbol === undefined) {
- return this.filterBySinceLimit (result, since, limit);
- }
- return this.filterBySymbolSinceLimit (result, symbol, since, limit);
+ return this.parseOrders (response, market, since, limit, {
+ 'status': 'open',
+ 'type': 'limit',
+ });
}
getCurrencyName (code) {
@@ -22947,18 +30179,12 @@ module.exports = class bitstamp extends Exchange {
}
isFiat (code) {
- if (code === 'USD') {
- return true;
- }
- if (code === 'EUR') {
- return true;
- }
- return false;
+ return code === 'USD' || code === 'EUR' || code === 'GBP';
}
async fetchDepositAddress (code, params = {}) {
if (this.isFiat (code)) {
- throw new NotSupported (this.id + ' fiat fetchDepositAddress() for ' + code + ' is not implemented yet');
+ throw new NotSupported (this.id + ' fiat fetchDepositAddress() for ' + code + ' is not supported!');
}
const name = this.getCurrencyName (code);
const v1 = (code === 'BTC');
@@ -22971,7 +30197,7 @@ module.exports = class bitstamp extends Exchange {
response = JSON.parse (response);
}
const address = v1 ? response : this.safeString (response, 'address');
- const tag = v1 ? undefined : this.safeString (response, 'destination_tag');
+ const tag = v1 ? undefined : this.safeString2 (response, 'memo_id', 'destination_tag');
this.checkAddress (address);
return {
'currency': code,
@@ -22982,22 +30208,30 @@ module.exports = class bitstamp extends Exchange {
}
async withdraw (code, amount, address, tag = undefined, params = {}) {
+ // For fiat withdrawals please provide all required additional parameters in the 'params'
+ // Check https://www.bitstamp.net/api/ under 'Open bank withdrawal' for list and description.
+ await this.loadMarkets ();
this.checkAddress (address);
- if (this.isFiat (code)) {
- throw new NotSupported (this.id + ' fiat withdraw() for ' + code + ' is not implemented yet');
- }
- const name = this.getCurrencyName (code);
const request = {
'amount': amount,
- 'address': address,
};
- const v1 = (code === 'BTC');
- let method = v1 ? 'v1' : 'private'; // v1 or v2
- method += 'Post' + this.capitalize (name) + 'Withdrawal';
- if (code === 'XRP') {
- if (tag !== undefined) {
- request['destination_tag'] = tag;
+ let method = undefined;
+ if (!this.isFiat (code)) {
+ const name = this.getCurrencyName (code);
+ const v1 = (code === 'BTC');
+ method = v1 ? 'v1' : 'private'; // v1 or v2
+ method += 'Post' + this.capitalize (name) + 'Withdrawal';
+ if (code === 'XRP') {
+ if (tag !== undefined) {
+ request['destination_tag'] = tag;
+ }
}
+ request['address'] = address;
+ } else {
+ method = 'privatePostWithdrawalOpen';
+ const currency = this.currency (code);
+ request['iban'] = address;
+ request['account_currency'] = currency['id'];
}
const response = await this[method] (this.extend (request, params));
return {
@@ -23123,7 +30357,7 @@ module.exports = class bitstamp extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],42:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],42:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -23142,7 +30376,15 @@ module.exports = class bitstamp1 extends Exchange {
'rateLimit': 1000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMyTrades': true,
+ 'fetchOrder': false,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27786377-8c8ab57e-5fe9-11e7-8ea4-2b05b6bcceec.jpg',
@@ -23185,18 +30427,18 @@ module.exports = class bitstamp1 extends Exchange {
},
},
'markets': {
- 'BTC/USD': { 'id': 'btcusd', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD', 'baseId': 'btc', 'quoteId': 'usd', 'maker': 0.0025, 'taker': 0.0025 },
- 'BTC/EUR': { 'id': 'btceur', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'btc', 'quoteId': 'eur', 'maker': 0.0025, 'taker': 0.0025 },
- 'EUR/USD': { 'id': 'eurusd', 'symbol': 'EUR/USD', 'base': 'EUR', 'quote': 'USD', 'baseId': 'eur', 'quoteId': 'usd', 'maker': 0.0025, 'taker': 0.0025 },
- 'XRP/USD': { 'id': 'xrpusd', 'symbol': 'XRP/USD', 'base': 'XRP', 'quote': 'USD', 'baseId': 'xrp', 'quoteId': 'usd', 'maker': 0.0025, 'taker': 0.0025 },
- 'XRP/EUR': { 'id': 'xrpeur', 'symbol': 'XRP/EUR', 'base': 'XRP', 'quote': 'EUR', 'baseId': 'xrp', 'quoteId': 'eur', 'maker': 0.0025, 'taker': 0.0025 },
- 'XRP/BTC': { 'id': 'xrpbtc', 'symbol': 'XRP/BTC', 'base': 'XRP', 'quote': 'BTC', 'baseId': 'xrp', 'quoteId': 'btc', 'maker': 0.0025, 'taker': 0.0025 },
- 'LTC/USD': { 'id': 'ltcusd', 'symbol': 'LTC/USD', 'base': 'LTC', 'quote': 'USD', 'baseId': 'ltc', 'quoteId': 'usd', 'maker': 0.0025, 'taker': 0.0025 },
- 'LTC/EUR': { 'id': 'ltceur', 'symbol': 'LTC/EUR', 'base': 'LTC', 'quote': 'EUR', 'baseId': 'ltc', 'quoteId': 'eur', 'maker': 0.0025, 'taker': 0.0025 },
- 'LTC/BTC': { 'id': 'ltcbtc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'baseId': 'ltc', 'quoteId': 'btc', 'maker': 0.0025, 'taker': 0.0025 },
- 'ETH/USD': { 'id': 'ethusd', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD', 'baseId': 'eth', 'quoteId': 'usd', 'maker': 0.0025, 'taker': 0.0025 },
- 'ETH/EUR': { 'id': 'etheur', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR', 'baseId': 'eth', 'quoteId': 'eur', 'maker': 0.0025, 'taker': 0.0025 },
- 'ETH/BTC': { 'id': 'ethbtc', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC', 'baseId': 'eth', 'quoteId': 'btc', 'maker': 0.0025, 'taker': 0.0025 },
+ 'BTC/USD': { 'id': 'btcusd', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD', 'baseId': 'btc', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
+ 'BTC/EUR': { 'id': 'btceur', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'btc', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
+ 'EUR/USD': { 'id': 'eurusd', 'symbol': 'EUR/USD', 'base': 'EUR', 'quote': 'USD', 'baseId': 'eur', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
+ 'XRP/USD': { 'id': 'xrpusd', 'symbol': 'XRP/USD', 'base': 'XRP', 'quote': 'USD', 'baseId': 'xrp', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
+ 'XRP/EUR': { 'id': 'xrpeur', 'symbol': 'XRP/EUR', 'base': 'XRP', 'quote': 'EUR', 'baseId': 'xrp', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
+ 'XRP/BTC': { 'id': 'xrpbtc', 'symbol': 'XRP/BTC', 'base': 'XRP', 'quote': 'BTC', 'baseId': 'xrp', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005 },
+ 'LTC/USD': { 'id': 'ltcusd', 'symbol': 'LTC/USD', 'base': 'LTC', 'quote': 'USD', 'baseId': 'ltc', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
+ 'LTC/EUR': { 'id': 'ltceur', 'symbol': 'LTC/EUR', 'base': 'LTC', 'quote': 'EUR', 'baseId': 'ltc', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
+ 'LTC/BTC': { 'id': 'ltcbtc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'baseId': 'ltc', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005 },
+ 'ETH/USD': { 'id': 'ethusd', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD', 'baseId': 'eth', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
+ 'ETH/EUR': { 'id': 'etheur', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR', 'baseId': 'eth', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
+ 'ETH/BTC': { 'id': 'ethbtc', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC', 'baseId': 'eth', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005 },
},
});
}
@@ -23416,13 +30658,13 @@ module.exports = class bitstamp1 extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],43:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],43:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { BadSymbol, ExchangeError, ExchangeNotAvailable, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound, DDoSProtection, PermissionDenied, AddressPending, OnMaintenance } = require ('./base/errors');
+const { BadSymbol, ExchangeError, ExchangeNotAvailable, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound, DDoSProtection, PermissionDenied, AddressPending, OnMaintenance, BadRequest } = require ('./base/errors');
const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -23433,50 +30675,53 @@ module.exports = class bittrex extends Exchange {
'id': 'bittrex',
'name': 'Bittrex',
'countries': [ 'US' ],
- 'version': 'v1.1',
+ 'version': 'v3',
'rateLimit': 1500,
'certified': true,
'pro': true,
// new metainfo interface
'has': {
'CORS': false,
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
'createMarketOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchDeposits': true,
'fetchDepositAddress': true,
'fetchClosedOrders': true,
'fetchCurrencies': true,
+ 'fetchMarkets': true,
'fetchMyTrades': 'emulated',
'fetchOHLCV': true,
'fetchOrder': true,
+ 'fetchOrderTrades': true,
+ 'fetchOrderBook': true,
'fetchOpenOrders': true,
+ 'fetchTicker': true,
'fetchTickers': true,
- 'withdraw': true,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTransactions': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
- '1m': 'oneMin',
- '5m': 'fiveMin',
- '30m': 'thirtyMin',
- '1h': 'hour',
- '1d': 'day',
+ '1m': 'MINUTE_1',
+ '5m': 'MINUTE_5',
+ '1h': 'HOUR_1',
+ '1d': 'DAY_1',
},
'hostname': 'bittrex.com',
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27766352-cf0b3c26-5ed5-11e7-82b7-f3826b7a97d8.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87153921-edf53180-c2c0-11ea-96b9-f2a9a95a455b.jpg',
'api': {
- 'public': 'https://{hostname}/api',
- 'account': 'https://{hostname}/api',
- 'market': 'https://{hostname}/api',
- 'v2': 'https://{hostname}/api/v2.0/pub',
- 'v3': 'https://api.bittrex.com/v3',
- 'v3public': 'https://api.bittrex.com/v3',
+ 'public': 'https://api.bittrex.com',
+ 'private': 'https://api.bittrex.com',
},
'www': 'https://bittrex.com',
'doc': [
- 'https://bittrex.github.io/api/',
'https://bittrex.github.io/api/v3',
- 'https://www.npmjs.com/package/bittrex-node',
],
'fees': [
'https://bittrex.zendesk.com/hc/en-us/articles/115003684371-BITTREX-SERVICE-FEES-AND-WITHDRAWAL-LIMITATIONS',
@@ -23485,15 +30730,33 @@ module.exports = class bittrex extends Exchange {
'referral': 'https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B',
},
'api': {
- 'v3': {
+ 'public': {
+ 'get': [
+ 'ping',
+ 'currencies',
+ 'currencies/{symbol}',
+ 'markets',
+ 'markets/tickers',
+ 'markets/summaries',
+ 'markets/{marketSymbol}',
+ 'markets/{marketSymbol}/summary',
+ 'markets/{marketSymbol}/orderbook',
+ 'markets/{marketSymbol}/trades',
+ 'markets/{marketSymbol}/ticker',
+ 'markets/{marketSymbol}/candles/{candleInterval}/recent',
+ 'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}/{month}/{day}',
+ 'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}/{month}',
+ 'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}',
+ ],
+ },
+ 'private': {
'get': [
'account',
+ 'account/volume',
'addresses',
'addresses/{currencySymbol}',
'balances',
'balances/{currencySymbol}',
- 'currencies',
- 'currencies/{symbol}',
'deposits/open',
'deposits/closed',
'deposits/ByTxId/{txId}',
@@ -23501,6 +30764,7 @@ module.exports = class bittrex extends Exchange {
'orders/closed',
'orders/open',
'orders/{orderId}',
+ 'orders/{orderId}/executions',
'ping',
'subaccounts/{subaccountId}',
'subaccounts',
@@ -23508,73 +30772,27 @@ module.exports = class bittrex extends Exchange {
'withdrawals/closed',
'withdrawals/ByTxId/{txId}',
'withdrawals/{withdrawalId}',
+ 'withdrawals/whitelistAddresses',
+ 'conditional-orders/{conditionalOrderId}',
+ 'conditional-orders/closed',
+ 'conditional-orders/open',
+ 'transfers/sent',
+ 'transfers/received',
+ 'transfers/{transferId}',
],
'post': [
'addresses',
'orders',
'subaccounts',
'withdrawals',
+ 'conditional-orders',
+ 'transfers',
],
'delete': [
+ 'orders/open',
'orders/{orderId}',
'withdrawals/{withdrawalId}',
- ],
- },
- 'v3public': {
- 'get': [
- 'markets',
- 'markets/summaries',
- 'markets/{marketSymbol}',
- 'markets/{marketSymbol}/summary',
- 'markets/{marketSymbol}/orderbook',
- 'markets/{marketSymbol}/trades',
- 'markets/{marketSymbol}/ticker',
- 'markets/{marketSymbol}/candles',
- ],
- },
- 'v2': {
- 'get': [
- 'currencies/GetBTCPrice',
- 'currencies/GetWalletHealth',
- 'general/GetLatestAlert',
- 'market/GetTicks',
- 'market/GetLatestTick',
- 'Markets/GetMarketSummaries',
- 'market/GetLatestTick',
- ],
- },
- 'public': {
- 'get': [
- 'currencies',
- 'markethistory',
- 'markets',
- 'marketsummaries',
- 'marketsummary',
- 'orderbook',
- 'ticker',
- ],
- },
- 'account': {
- 'get': [
- 'balance',
- 'balances',
- 'depositaddress',
- 'deposithistory',
- 'order',
- 'orders',
- 'orderhistory',
- 'withdrawalhistory',
- 'withdraw',
- ],
- },
- 'market': {
- 'get': [
- 'buylimit',
- 'buymarket',
- 'cancel',
- 'openorders',
- 'selllimit',
- 'sellmarket',
+ 'conditional-orders/{conditionalOrderId}',
],
},
},
@@ -23588,46 +30806,12 @@ module.exports = class bittrex extends Exchange {
'funding': {
'tierBased': false,
'percentage': false,
- 'withdraw': {
- 'BTC': 0.0005,
- 'LTC': 0.01,
- 'DOGE': 2,
- 'VTC': 0.02,
- 'PPC': 0.02,
- 'FTC': 0.2,
- 'RDD': 2,
- 'NXT': 2,
- 'DASH': 0.05,
- 'POT': 0.002,
- 'BLK': 0.02,
- 'EMC2': 0.2,
- 'XMY': 0.2,
- 'GLD': 0.0002,
- 'SLR': 0.2,
- 'GRS': 0.2,
- },
- 'deposit': {
- 'BTC': 0,
- 'LTC': 0,
- 'DOGE': 0,
- 'VTC': 0,
- 'PPC': 0,
- 'FTC': 0,
- 'RDD': 0,
- 'NXT': 0,
- 'DASH': 0,
- 'POT': 0,
- 'BLK': 0,
- 'EMC2': 0,
- 'XMY': 0,
- 'GLD': 0,
- 'SLR': 0,
- 'GRS': 0,
- },
},
},
'exceptions': {
'exact': {
+ 'BAD_REQUEST': BadRequest, // {"code":"BAD_REQUEST","detail":"Refer to the data field for specific field validation failures.","data":{"invalidRequestParameter":"day"}}
+ 'STARTDATE_OUT_OF_RANGE': BadRequest, // {"code":"STARTDATE_OUT_OF_RANGE"}
// 'Call to Cancel was throttled. Try again in 60 seconds.': DDoSProtection,
// 'Call to GetBalances was throttled. Try again in 60 seconds.': DDoSProtection,
'APISIGN_NOT_PROVIDED': AuthenticationError,
@@ -23656,9 +30840,14 @@ module.exports = class bittrex extends Exchange {
},
},
'options': {
+ 'fetchTicker': {
+ 'method': 'publicGetMarketsMarketSymbolTicker', // publicGetMarketsMarketSymbolSummary
+ },
+ 'fetchTickers': {
+ 'method': 'publicGetMarketsTickers', // publicGetMarketsSummaries
+ },
'parseOrderStatus': false,
'hasAlreadyAuthenticatedSuccessfully': false, // a workaround for APIKEY_INVALID
- 'symbolSeparator': '-',
// With certain currencies, like
// AEON, BTS, GXS, NXT, SBD, STEEM, STR, XEM, XLM, XMR, XRP
// an additional tag / memo / payment id is usually required by exchanges.
@@ -23680,12 +30869,12 @@ module.exports = class bittrex extends Exchange {
},
'subaccountId': undefined,
// see the implementation of fetchClosedOrdersV3 below
- 'fetchClosedOrdersMethod': 'fetch_closed_orders_v3',
+ // 'fetchClosedOrdersMethod': 'fetch_closed_orders_v3',
'fetchClosedOrdersFilterBySince': true,
// 'createOrderMethod': 'create_order_v1',
},
'commonCurrencies': {
- 'BITS': 'SWIFT',
+ 'REPV2': 'REP',
},
});
}
@@ -23699,7 +30888,7 @@ module.exports = class bittrex extends Exchange {
}
async fetchMarkets (params = {}) {
- const response = await this.v3publicGetMarkets (params);
+ const response = await this.publicGetMarkets (params);
//
// [
// {
@@ -23724,17 +30913,11 @@ module.exports = class bittrex extends Exchange {
// ]
//
const result = [];
- // const markets = this.safeValue (response, 'result');
for (let i = 0; i < response.length; i++) {
const market = response[i];
const baseId = this.safeString (market, 'baseCurrencySymbol');
const quoteId = this.safeString (market, 'quoteCurrencySymbol');
- // bittrex v2 uses inverted pairs, v3 uses regular pairs
- // we use v3 for fetchMarkets and v2 throughout the rest of this implementation
- // therefore we swap the base ←→ quote here to be v2-compatible
- // https://github.com/ccxt/ccxt/issues/5634
- // const id = this.safeString (market, 'symbol');
- const id = quoteId + this.options['symbolSeparator'] + baseId;
+ const id = this.safeString (market, 'symbol');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
@@ -23761,7 +30944,11 @@ module.exports = class bittrex extends Exchange {
'max': undefined,
},
'price': {
- 'min': Math.pow (10, -precision['price']),
+ 'min': 1 / Math.pow (10, precision['price']),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
'max': undefined,
},
},
@@ -23772,18 +30959,17 @@ module.exports = class bittrex extends Exchange {
async fetchBalance (params = {}) {
await this.loadMarkets ();
- const response = await this.accountGetBalances (params);
- const balances = this.safeValue (response, 'result');
+ const balances = await this.privateGetBalances (params);
const result = { 'info': balances };
- const indexed = this.indexBy (balances, 'Currency');
+ const indexed = this.indexBy (balances, 'currencySymbol');
const currencyIds = Object.keys (indexed);
for (let i = 0; i < currencyIds.length; i++) {
const currencyId = currencyIds[i];
const code = this.safeCurrencyCode (currencyId);
const account = this.account ();
const balance = indexed[currencyId];
- account['free'] = this.safeFloat (balance, 'Available');
- account['total'] = this.safeFloat (balance, 'Balance');
+ account['free'] = this.safeFloat (balance, 'available');
+ account['total'] = this.safeFloat (balance, 'total');
result[code] = account;
}
return this.parseBalance (result);
@@ -23792,75 +30978,79 @@ module.exports = class bittrex extends Exchange {
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {
- 'market': this.marketId (symbol),
- 'type': 'both',
+ 'marketSymbol': this.marketId (symbol),
};
- const response = await this.publicGetOrderbook (this.extend (request, params));
- let orderbook = response['result'];
- if ('type' in params) {
- if (params['type'] === 'buy') {
- orderbook = {
- 'buy': response['result'],
- 'sell': [],
- };
- } else if (params['type'] === 'sell') {
- orderbook = {
- 'buy': [],
- 'sell': response['result'],
- };
+ if (limit !== undefined) {
+ if ((limit !== 1) && (limit !== 25) && (limit !== 500)) {
+ throw new BadRequest (this.id + ' fetchOrderBook() limit argument must be undefined, 1, 25 or 500, default is 25');
}
+ request['depth'] = limit;
}
- return this.parseOrderBook (orderbook, undefined, 'buy', 'sell', 'Rate', 'Quantity');
+ const response = await this.publicGetMarketsMarketSymbolOrderbook (this.extend (request, params));
+ //
+ // {
+ // "bid":[
+ // {"quantity":"0.01250000","rate":"10718.56200003"},
+ // {"quantity":"0.10000000","rate":"10718.56200002"},
+ // {"quantity":"0.39648292","rate":"10718.56200001"},
+ // ],
+ // "ask":[
+ // {"quantity":"0.05100000","rate":"10724.30099631"},
+ // {"quantity":"0.10000000","rate":"10724.30099632"},
+ // {"quantity":"0.26000000","rate":"10724.30099634"},
+ // ]
+ // }
+ //
+ const sequence = this.safeInteger (this.last_response_headers, 'Sequence');
+ const orderbook = this.parseOrderBook (response, undefined, 'bid', 'ask', 'rate', 'quantity');
+ orderbook['nonce'] = sequence;
+ return orderbook;
}
async fetchCurrencies (params = {}) {
const response = await this.publicGetCurrencies (params);
//
- // {
- // "success": true,
- // "message": "",
- // "result": [
- // {
- // "Currency": "BTC",
- // "CurrencyLong":"Bitcoin",
- // "MinConfirmation":2,
- // "TxFee":0.00050000,
- // "IsActive":true,
- // "IsRestricted":false,
- // "CoinType":"BITCOIN",
- // "BaseAddress":"1N52wHoVR79PMDishab2XmRHsbekCdGquK",
- // "Notice":null
- // },
- // ...,
- // ]
- // }
+ // [
+ // {
+ // "symbol":"1ST",
+ // "name":"Firstblood",
+ // "coinType":"ETH_CONTRACT",
+ // "status":"ONLINE",
+ // "minConfirmations":36,
+ // "notice":"",
+ // "txFee":"4.50000000",
+ // "logoUrl":"https://bittrexblobstorage.blob.core.windows.net/public/5685a7be-1edf-4ba0-a313-b5309bb204f8.png",
+ // "prohibitedIn":[],
+ // "baseAddress":"0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98",
+ // "associatedTermsOfService":[]
+ // }
+ // ]
//
- const currencies = this.safeValue (response, 'result', []);
const result = {};
- for (let i = 0; i < currencies.length; i++) {
- const currency = currencies[i];
- const id = this.safeString (currency, 'Currency');
+ for (let i = 0; i < response.length; i++) {
+ const currency = response[i];
+ const id = this.safeString (currency, 'symbol');
const code = this.safeCurrencyCode (id);
const precision = 8; // default precision, todo: fix "magic constants"
- const address = this.safeValue (currency, 'BaseAddress');
- const fee = this.safeFloat (currency, 'TxFee'); // todo: redesign
+ const fee = this.safeFloat (currency, 'txFee'); // todo: redesign
+ const isActive = this.safeString (currency, 'status');
result[code] = {
'id': id,
'code': code,
- 'address': address,
+ 'address': this.safeString (currency, 'baseAddress'),
'info': currency,
- 'type': this.safeString (currency, 'CoinType'),
- 'name': this.safeString (currency, 'CurrencyLong'),
- 'active': this.safeValue (currency, 'IsActive'),
+ 'type': this.safeString (currency, 'coinType'),
+ 'name': this.safeString (currency, 'name'),
+ 'active': (isActive === 'ONLINE'),
'fee': fee,
'precision': precision,
'limits': {
'amount': {
- 'min': Math.pow (10, -precision),
+ 'min': 1 / Math.pow (10, precision),
'max': undefined,
},
'price': {
- 'min': Math.pow (10, -precision),
+ 'min': 1 / Math.pow (10, precision),
'max': undefined,
},
'cost': {
@@ -23878,79 +31068,93 @@ module.exports = class bittrex extends Exchange {
}
parseTicker (ticker, market = undefined) {
+ //
+ // ticker
//
// {
- // "MarketName":"BTC-ETH",
- // "High":0.02127099,
- // "Low":0.02035064,
- // "Volume":10288.40271571,
- // "Last":0.02070510,
- // "BaseVolume":214.64663206,
- // "TimeStamp":"2019-09-18T21:03:59.897",
- // "Bid":0.02070509,
- // "Ask":0.02070510,
- // "OpenBuyOrders":1228,
- // "OpenSellOrders":5899,
- // "PrevDay":0.02082823,
- // "Created":"2015-08-14T09:02:24.817"
+ // "symbol":"ETH-BTC",
+ // "lastTradeRate":"0.03284496",
+ // "bidRate":"0.03284523",
+ // "askRate":"0.03286857"
// }
//
- const timestamp = this.parse8601 (this.safeString (ticker, 'TimeStamp'));
- let symbol = undefined;
- const marketId = this.safeString (ticker, 'MarketName');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- symbol = this.parseSymbol (marketId);
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
- const previous = this.safeFloat (ticker, 'PrevDay');
- const last = this.safeFloat (ticker, 'Last');
- let change = undefined;
- let percentage = undefined;
- if (last !== undefined) {
- if (previous !== undefined) {
- change = last - previous;
- if (previous > 0) {
- percentage = (change / previous) * 100;
- }
- }
- }
+ // summary
+ //
+ // {
+ // "symbol":"ETH-BTC",
+ // "high":"0.03369528",
+ // "low":"0.03282442",
+ // "volume":"4307.83794556",
+ // "quoteVolume":"143.08608869",
+ // "percentChange":"0.79",
+ // "updatedAt":"2020-09-29T07:36:57.823Z"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (ticker, 'updatedAt'));
+ const marketId = this.safeString (ticker, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const percentage = this.safeFloat (ticker, 'percentChange');
+ const last = this.safeFloat (ticker, 'lastTradeRate');
return {
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'high': this.safeFloat (ticker, 'High'),
- 'low': this.safeFloat (ticker, 'Low'),
- 'bid': this.safeFloat (ticker, 'Bid'),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': this.safeFloat (ticker, 'bidRate'),
'bidVolume': undefined,
- 'ask': this.safeFloat (ticker, 'Ask'),
+ 'ask': this.safeFloat (ticker, 'askRate'),
'askVolume': undefined,
'vwap': undefined,
- 'open': previous,
+ 'open': undefined,
'close': last,
'last': last,
'previousClose': undefined,
- 'change': change,
+ 'change': undefined,
'percentage': percentage,
'average': undefined,
- 'baseVolume': this.safeFloat (ticker, 'Volume'),
- 'quoteVolume': this.safeFloat (ticker, 'BaseVolume'),
+ 'baseVolume': this.safeFloat (ticker, 'volume'),
+ 'quoteVolume': this.safeFloat (ticker, 'quoteVolume'),
'info': ticker,
};
}
async fetchTickers (symbols = undefined, params = {}) {
await this.loadMarkets ();
- const response = await this.publicGetMarketsummaries (params);
- const result = this.safeValue (response, 'result');
+ const options = this.safeValue (this.options, 'fetchTickers', {});
+ const defaultMethod = this.safeString (options, 'method', 'publicGetMarketsTickers');
+ const method = this.safeString (params, 'method', defaultMethod);
+ params = this.omit (params, 'method');
+ const response = await this[method] (params);
+ //
+ // publicGetMarketsTickers
+ //
+ // [
+ // {
+ // "symbol":"4ART-BTC",
+ // "lastTradeRate":"0.00000210",
+ // "bidRate":"0.00000210",
+ // "askRate":"0.00000215"
+ // }
+ // ]
+ //
+ // publicGetMarketsSummaries
+ //
+ // [
+ // {
+ // "symbol":"4ART-BTC",
+ // "high":"0.00000206",
+ // "low":"0.00000196",
+ // "volume":"14871.32000233",
+ // "quoteVolume":"0.02932756",
+ // "percentChange":"1.48",
+ // "updatedAt":"2020-09-29T07:34:32.757Z"
+ // }
+ // ]
+ //
const tickers = [];
- for (let i = 0; i < result.length; i++) {
- const ticker = this.parseTicker (result[i]);
+ for (let i = 0; i < response.length; i++) {
+ const ticker = this.parseTicker (response[i]);
tickers.push (ticker);
}
return this.filterByArray (tickers, 'symbol', symbols);
@@ -23960,114 +31164,211 @@ module.exports = class bittrex extends Exchange {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
- 'market': market['id'],
+ 'marketSymbol': market['id'],
};
- const response = await this.publicGetMarketsummary (this.extend (request, params));
+ const options = this.safeValue (this.options, 'fetchTicker', {});
+ const defaultMethod = this.safeString (options, 'method', 'publicGetMarketsMarketSymbolTicker');
+ const method = this.safeString (params, 'method', defaultMethod);
+ params = this.omit (params, 'method');
+ const response = await this[method] (this.extend (request, params));
+ //
+ // publicGetMarketsMarketSymbolTicker
//
// {
- // "success":true,
- // "message":"",
- // "result":[
- // {
- // "MarketName":"BTC-ETH",
- // "High":0.02127099,
- // "Low":0.02035064,
- // "Volume":10288.40271571,
- // "Last":0.02070510,
- // "BaseVolume":214.64663206,
- // "TimeStamp":"2019-09-18T21:03:59.897",
- // "Bid":0.02070509,
- // "Ask":0.02070510,
- // "OpenBuyOrders":1228,
- // "OpenSellOrders":5899,
- // "PrevDay":0.02082823,
- // "Created":"2015-08-14T09:02:24.817"
- // }
- // ]
+ // "symbol":"ETH-BTC",
+ // "lastTradeRate":"0.03284496",
+ // "bidRate":"0.03284523",
+ // "askRate":"0.03286857"
// }
//
- const ticker = response['result'][0];
- return this.parseTicker (ticker, market);
+ //
+ // publicGetMarketsMarketSymbolSummary
+ //
+ // {
+ // "symbol":"ETH-BTC",
+ // "high":"0.03369528",
+ // "low":"0.03282442",
+ // "volume":"4307.83794556",
+ // "quoteVolume":"143.08608869",
+ // "percentChange":"0.79",
+ // "updatedAt":"2020-09-29T07:36:57.823Z"
+ // }
+ //
+ return this.parseTicker (response, market);
}
parseTrade (trade, market = undefined) {
- const timestamp = this.parse8601 (trade['TimeStamp'] + '+00:00');
- let side = undefined;
- if (trade['OrderType'] === 'BUY') {
- side = 'buy';
- } else if (trade['OrderType'] === 'SELL') {
- side = 'sell';
- }
- const id = this.safeString2 (trade, 'Id', 'ID');
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ //
+ // public fetchTrades
+ //
+ // {
+ // "id":"9c5589db-42fb-436c-b105-5e2edcb95673",
+ // "executedAt":"2020-10-03T11:48:43.38Z",
+ // "quantity":"0.17939626",
+ // "rate":"0.03297952",
+ // "takerSide":"BUY"
+ // }
+ //
+ // private fetchOrderTrades
+ //
+ // {
+ // "id": "aaa3e9bd-5b86-4a21-8b3d-1275c1d30b8e",
+ // "marketSymbol": "OMG-BTC",
+ // "executedAt": "2020-10-02T16:00:30.3Z",
+ // "quantity": "7.52710000",
+ // "rate": "0.00034907",
+ // "orderId": "3a3dbd33-3a30-4ae5-a41d-68d3c1ac537e",
+ // "commission": "0.00000525",
+ // "isTaker": false
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (trade, 'executedAt'));
+ const id = this.safeString (trade, 'id');
+ const order = this.safeString (trade, 'orderId');
+ const marketId = this.safeString (trade, 'marketSymbol');
+ market = this.safeMarket (marketId, market, '-');
let cost = undefined;
- const price = this.safeFloat (trade, 'Price');
- const amount = this.safeFloat (trade, 'Quantity');
+ const price = this.safeFloat (trade, 'rate');
+ const amount = this.safeFloat (trade, 'quantity');
if (amount !== undefined) {
if (price !== undefined) {
cost = price * amount;
}
}
+ let takerOrMaker = undefined;
+ const isTaker = this.safeValue (trade, 'isTaker');
+ if (isTaker !== undefined) {
+ takerOrMaker = isTaker ? 'taker' : 'maker';
+ }
+ let fee = undefined;
+ const feeCost = this.safeFloat (trade, 'commission');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': market['quote'],
+ };
+ }
+ const side = this.safeStringLower (trade, 'takerSide');
return {
'info': trade,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'id': id,
- 'order': undefined,
- 'type': 'limit',
- 'takerOrMaker': undefined,
+ 'order': order,
+ 'takerOrMaker': takerOrMaker,
+ 'type': undefined,
'side': side,
'price': price,
'amount': amount,
'cost': cost,
- 'fee': undefined,
+ 'fee': fee,
};
}
+ async fetchTime (params = {}) {
+ const response = await this.publicGetPing (params);
+ //
+ // {
+ // "serverTime": 1594596023162
+ // }
+ //
+ return this.safeInteger (response, 'serverTime');
+ }
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
- 'market': market['id'],
+ 'marketSymbol': this.marketId (symbol),
};
- const response = await this.publicGetMarkethistory (this.extend (request, params));
- if ('result' in response) {
- if (response['result'] !== undefined) {
- return this.parseTrades (response['result'], market, since, limit);
- }
- }
- throw new ExchangeError (this.id + ' fetchTrades() returned undefined response');
+ const response = await this.publicGetMarketsMarketSymbolTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id":"9c5589db-42fb-436c-b105-5e2edcb95673",
+ // "executedAt":"2020-10-03T11:48:43.38Z",
+ // "quantity":"0.17939626",
+ // "rate":"0.03297952",
+ // "takerSide":"BUY"
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
- const timestamp = this.parse8601 (ohlcv['T'] + '+00:00');
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "startsAt":"2020-06-12T02:35:00Z",
+ // "open":"0.02493753",
+ // "high":"0.02493753",
+ // "low":"0.02493753",
+ // "close":"0.02493753",
+ // "volume":"0.09590123",
+ // "quoteVolume":"0.00239153"
+ // }
+ //
return [
- timestamp,
- ohlcv['O'],
- ohlcv['H'],
- ohlcv['L'],
- ohlcv['C'],
- ohlcv['V'],
+ this.parse8601 (this.safeString (ohlcv, 'startsAt')),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'volume'),
];
}
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
+ const reverseId = market['baseId'] + '-' + market['quoteId'];
const request = {
- 'tickInterval': this.timeframes[timeframe],
- 'marketName': market['id'],
+ 'candleInterval': this.timeframes[timeframe],
+ 'marketSymbol': reverseId,
};
- const response = await this.v2GetMarketGetTicks (this.extend (request, params));
- if ('result' in response) {
- if (response['result']) {
- return this.parseOHLCVs (response['result'], market, timeframe, since, limit);
+ let method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalRecent';
+ if (since !== undefined) {
+ const now = this.milliseconds ();
+ const difference = Math.abs (now - since);
+ const sinceDate = this.ymd (since);
+ const parts = sinceDate.split ('-');
+ const sinceYear = this.safeInteger (parts, 0);
+ const sinceMonth = this.safeInteger (parts, 1);
+ const sinceDay = this.safeInteger (parts, 2);
+ if (timeframe === '1d') {
+ // if the since argument is beyond one year into the past
+ if (difference > 31622400000) {
+ method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYear';
+ request['year'] = sinceYear;
+ }
+ // request['year'] = year;
+ } else if (timeframe === '1h') {
+ // if the since argument is beyond 31 days into the past
+ if (difference > 2678400000) {
+ method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYearMonth';
+ request['year'] = sinceYear;
+ request['month'] = sinceMonth;
+ }
+ } else {
+ // if the since argument is beyond 1 day into the past
+ if (difference > 86400000) {
+ method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYearMonthDay';
+ request['year'] = sinceYear;
+ request['month'] = sinceMonth;
+ request['day'] = sinceDay;
+ }
}
}
+ const response = await this[method] (this.extend (request, params));
+ //
+ // [
+ // {"startsAt":"2020-06-12T02:35:00Z","open":"0.02493753","high":"0.02493753","low":"0.02493753","close":"0.02493753","volume":"0.09590123","quoteVolume":"0.00239153"},
+ // {"startsAt":"2020-06-12T02:40:00Z","open":"0.02491874","high":"0.02491874","low":"0.02490970","close":"0.02490970","volume":"0.04515695","quoteVolume":"0.00112505"},
+ // {"startsAt":"2020-06-12T02:45:00Z","open":"0.02490753","high":"0.02493143","low":"0.02490753","close":"0.02493143","volume":"0.17769640","quoteVolume":"0.00442663"}
+ // ]
+ //
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -24076,26 +31377,26 @@ module.exports = class bittrex extends Exchange {
let market = undefined;
if (symbol !== undefined) {
market = this.market (symbol);
- request['market'] = market['id'];
+ request['marketSymbol'] = market['id'];
}
- const response = await this.marketGetOpenorders (this.extend (request, params));
- const result = this.safeValue (response, 'result', []);
- const orders = this.parseOrders (result, market, since, limit);
- return this.filterBySymbol (orders, symbol);
+ const response = await this.privateGetOrdersOpen (this.extend (request, params));
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'orderId': id,
+ };
+ const response = await this.privateGetOrdersOrderIdExecutions (this.extend (request, params));
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ return this.parseTrades (response, market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- const uppercaseType = type.toUpperCase ();
- const isMarket = (uppercaseType === 'MARKET');
- const isCeilingLimit = (uppercaseType === 'CEILING_LIMIT');
- const isCeilingMarket = (uppercaseType === 'CEILING_MARKET');
- const isV3 = isMarket || isCeilingLimit || isCeilingMarket;
- const defaultMethod = isV3 ? 'create_order_v3' : 'create_order_v1';
- const method = this.safeValue (this.options, 'createOrderMethod', defaultMethod);
- return await this[method] (symbol, type, side, amount, price, params);
- }
-
- async createOrderV3 (symbol, type, side, amount, price = undefined, params = {}) {
// A ceiling order is a market or limit order that allows you to specify
// the amount of quote currency you want to spend (or receive, if selling)
// instead of the quantity of the market currency (e.g. buy $100 USD of BTC
@@ -24131,7 +31432,7 @@ module.exports = class bittrex extends Exchange {
request['timeInForce'] = 'IMMEDIATE_OR_CANCEL';
}
}
- const response = await this.v3PostOrders (this.extend (request, params));
+ const response = await this.privatePostOrders (this.extend (request, params));
//
// {
// id: 'f03d5e98-b5ac-48fb-8647-dd4db828a297',
@@ -24149,63 +31450,63 @@ module.exports = class bittrex extends Exchange {
// updatedAt: '2020-03-18T02:37:33.42Z'
// }
//
- return this.parseOrderV3 (response, market);
- }
-
- async createOrderV1 (symbol, type, side, amount, price = undefined, params = {}) {
- if (type !== 'limit') {
- throw new ExchangeError (this.id + ' allows limit orders only');
- }
- await this.loadMarkets ();
- const market = this.market (symbol);
- const method = 'marketGet' + this.capitalize (side) + type;
- const request = {
- 'market': market['id'],
- 'quantity': this.amountToPrecision (symbol, amount),
- 'rate': this.priceToPrecision (symbol, price),
- };
- // if (type == 'limit')
- // order['rate'] = this.priceToPrecision (symbol, price);
- const response = await this[method] (this.extend (request, params));
- const orderIdField = this.getOrderIdField ();
- const orderId = this.safeString (response['result'], orderIdField);
- return {
- 'info': response,
- 'id': orderId,
- 'symbol': symbol,
- 'type': type,
- 'side': side,
- 'status': 'open',
- };
- }
-
- getOrderIdField () {
- return 'uuid';
+ return this.parseOrder (response, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- const orderIdField = this.getOrderIdField ();
- const request = {};
- request[orderIdField] = id;
- const response = await this.marketGetCancel (this.extend (request, params));
- //
- // {
- // "success": true,
- // "message": "''",
- // "result": {
- // "uuid": "614c34e4-8d71-11e3-94b5-425861b86ab6"
- // }
- // }
- //
- const result = this.safeValue (response, 'result', {});
- return this.extend (this.parseOrder (result), {
+ const request = {
+ 'orderId': id,
+ };
+ const response = await this.privateDeleteOrdersOrderId (this.extend (request, params));
+ return this.extend (this.parseOrder (response), {
'id': id,
'info': response,
'status': 'canceled',
});
}
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['marketSymbol'] = market['id'];
+ }
+ const response = await this.privateDeleteOrdersOpen (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id":"66582be0-5337-4d8c-b212-c356dd525801",
+ // "statusCode":"SUCCESS",
+ // "result":{
+ // "id":"66582be0-5337-4d8c-b212-c356dd525801",
+ // "marketSymbol":"BTC-USDT",
+ // "direction":"BUY",
+ // "type":"LIMIT",
+ // "quantity":"0.01000000",
+ // "limit":"3000.00000000",
+ // "timeInForce":"GOOD_TIL_CANCELLED",
+ // "fillQuantity":"0.00000000",
+ // "commission":"0.00000000",
+ // "proceeds":"0.00000000",
+ // "status":"CLOSED",
+ // "createdAt":"2020-10-06T12:31:53.39Z",
+ // "updatedAt":"2020-10-06T12:54:28.8Z",
+ // "closedAt":"2020-10-06T12:54:28.8Z"
+ // }
+ // }
+ // ]
+ //
+ const orders = [];
+ for (let i = 0; i < response.length; i++) {
+ const result = this.safeValue (response[i], 'result', {});
+ orders.push (result);
+ }
+ return this.parseOrders (orders, market);
+ }
+
async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
// https://support.bittrex.com/hc/en-us/articles/115003723911
@@ -24213,24 +31514,13 @@ module.exports = class bittrex extends Exchange {
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
- request['currency'] = currency['id'];
+ request['currencySymbol'] = currency['id'];
}
- const response = await this.accountGetDeposithistory (this.extend (request, params));
- //
- // { success: true,
- // message: "",
- // result: [ { Id: 22578097,
- // Amount: 0.3,
- // Currency: "ETH",
- // Confirmations: 15,
- // LastUpdated: "2018-06-10T07:12:10.57",
- // TxId: "0xf50b5ba2ca5438b58f93516eaa523eaf35b4420ca0f24061003df1be7…",
- // CryptoAddress: "0xb25f281fa51f1635abd4a60b0870a62d2a7fa404" } ] }
- //
+ const response = await this.privateGetDepositsClosed (this.extend (request, params));
// we cannot filter by `since` timestamp, as it isn't set by Bittrex
// see https://github.com/ccxt/ccxt/issues/4067
- // return this.parseTransactions (response['result'], currency, since, limit);
- return this.parseTransactions (response['result'], currency, undefined, limit);
+ // return this.parseTransactions (response, currency, since, limit);
+ return this.parseTransactions (response, currency, undefined, limit);
}
async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
@@ -24240,60 +31530,29 @@ module.exports = class bittrex extends Exchange {
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
- request['currency'] = currency['id'];
+ request['currencySymbol'] = currency['id'];
}
- const response = await this.accountGetWithdrawalhistory (this.extend (request, params));
- //
- // {
- // "success" : true,
- // "message" : "",
- // "result" : [{
- // "PaymentUuid" : "b32c7a5c-90c6-4c6e-835c-e16df12708b1",
- // "Currency" : "BTC",
- // "Amount" : 17.00000000,
- // "Address" : "1DfaaFBdbB5nrHj87x3NHS4onvw1GPNyAu",
- // "Opened" : "2014-07-09T04:24:47.217",
- // "Authorized" : true,
- // "PendingPayment" : false,
- // "TxCost" : 0.00020000,
- // "TxId" : null,
- // "Canceled" : true,
- // "InvalidAddress" : false
- // }, {
- // "PaymentUuid" : "d193da98-788c-4188-a8f9-8ec2c33fdfcf",
- // "Currency" : "XC",
- // "Amount" : 7513.75121715,
- // "Address" : "TcnSMgAd7EonF2Dgc4c9K14L12RBaW5S5J",
- // "Opened" : "2014-07-08T23:13:31.83",
- // "Authorized" : true,
- // "PendingPayment" : false,
- // "TxCost" : 0.00002000,
- // "TxId" : "d8a575c2a71c7e56d02ab8e26bb1ef0a2f6cf2094f6ca2116476a569c1e84f6e",
- // "Canceled" : false,
- // "InvalidAddress" : false
- // }
- // ]
- // }
- //
- return this.parseTransactions (response['result'], currency, since, limit);
+ const response = await this.privateGetWithdrawalsClosed (this.extend (request, params));
+ return this.parseTransactions (response, currency, since, limit);
}
parseTransaction (transaction, currency = undefined) {
//
// fetchDeposits
- //
// {
- // Id: 72578097,
- // Amount: 0.3,
- // Currency: "ETH",
- // Confirmations: 15,
- // LastUpdated: "2018-06-17T07:12:14.57",
- // TxId: "0xb31b5ba2ca5438b58f93516eaa523eaf35b4420ca0f24061003df1be7…",
- // CryptoAddress: "0x2d5f281fa51f1635abd4a60b0870a62d2a7fa404"
+ // "id": "d00fdf2e-df9e-48f1-....",
+ // "currencySymbol": "BTC",
+ // "quantity": "0.00550000",
+ // "cryptoAddress": "1PhmYjnJPZH5NUwV8AU...",
+ // "txId": "d1f1afffe1b9b6614eaee7e8133c85d98...",
+ // "confirmations": 2,
+ // "updatedAt": "2020-01-12T16:49:30.41Z",
+ // "completedAt": "2020-01-12T16:49:30.41Z",
+ // "status": "COMPLETED",
+ // "source": "BLOCKCHAIN"
// }
//
// fetchWithdrawals
- //
// {
// "PaymentUuid" : "e293da98-788c-4188-a8f9-8ec2c33fdfcf",
// "Currency" : "XC",
@@ -24308,15 +31567,15 @@ module.exports = class bittrex extends Exchange {
// "InvalidAddress" : false
// }
//
- const id = this.safeString2 (transaction, 'Id', 'PaymentUuid');
- const amount = this.safeFloat (transaction, 'Amount');
- const address = this.safeString2 (transaction, 'CryptoAddress', 'Address');
- const txid = this.safeString (transaction, 'TxId');
- const updated = this.parse8601 (this.safeString (transaction, 'LastUpdated'));
- const opened = this.parse8601 (this.safeString (transaction, 'Opened'));
+ const id = this.safeString (transaction, 'id');
+ const amount = this.safeFloat (transaction, 'quantity');
+ const address = this.safeString (transaction, 'cryptoAddress');
+ const txid = this.safeString (transaction, 'txId');
+ const updated = this.parse8601 (this.safeString (transaction, 'updatedAt'));
+ const opened = this.parse8601 (this.safeString (transaction, 'createdAt'));
const timestamp = opened ? opened : updated;
const type = (opened === undefined) ? 'deposit' : 'withdrawal';
- const currencyId = this.safeString (transaction, 'Currency');
+ const currencyId = this.safeString (transaction, 'currencySymbol');
const code = this.safeCurrencyCode (currencyId, currency);
let status = 'pending';
if (type === 'deposit') {
@@ -24332,25 +31591,24 @@ module.exports = class bittrex extends Exchange {
//
status = 'ok';
} else {
- const authorized = this.safeValue (transaction, 'Authorized', false);
- const pendingPayment = this.safeValue (transaction, 'PendingPayment', false);
- const canceled = this.safeValue (transaction, 'Canceled', false);
- const invalidAddress = this.safeValue (transaction, 'InvalidAddress', false);
- if (invalidAddress) {
+ const responseStatus = this.safeString (transaction, 'status');
+ if (responseStatus === 'ERROR_INVALID_ADDRESS') {
status = 'failed';
- } else if (canceled) {
+ } else if (responseStatus === 'CANCELLED') {
status = 'canceled';
- } else if (pendingPayment) {
+ } else if (responseStatus === 'PENDING') {
status = 'pending';
- } else if (authorized && (txid !== undefined)) {
+ } else if (responseStatus === 'COMPLETED') {
+ status = 'ok';
+ } else if (responseStatus === 'AUTHORIZED' && (txid !== undefined)) {
status = 'ok';
}
}
- let feeCost = this.safeFloat (transaction, 'TxCost');
+ let feeCost = this.safeFloat (transaction, 'txCost');
if (feeCost === undefined) {
if (type === 'deposit') {
// according to https://support.bittrex.com/hc/en-us/articles/115000199651-What-fees-does-Bittrex-charge-
- feeCost = 0; // FIXME: remove hardcoded value that may change any time
+ feeCost = 0;
}
}
return {
@@ -24373,40 +31631,17 @@ module.exports = class bittrex extends Exchange {
};
}
- parseSymbol (id) {
- const [ quoteId, baseId ] = id.split (this.options['symbolSeparator']);
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- return base + '/' + quote;
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'GOOD_TIL_CANCELLED': 'GTC',
+ 'IMMEDIATE_OR_CANCEL': 'IOC',
+ 'FILL_OR_KILL': 'FOK',
+ 'POST_ONLY_GOOD_TIL_CANCELLED': 'POST_ONLY_GOOD_TIL_CANCELLED',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
}
parseOrder (order, market = undefined) {
- if ('marketSymbol' in order) {
- return this.parseOrderV3 (order, market);
- } else {
- return this.parseOrderV2 (order, market);
- }
- }
-
- parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
- if (this.options['fetchClosedOrdersFilterBySince']) {
- return super.parseOrders (orders, market, since, limit, params);
- } else {
- return super.parseOrders (orders, market, undefined, limit, params);
- }
- }
-
- parseOrderStatus (status) {
- const statuses = {
- 'CLOSED': 'closed',
- 'OPEN': 'open',
- 'CANCELLED': 'canceled',
- 'CANCELED': 'canceled',
- };
- return this.safeString (statuses, status, status);
- }
-
- parseOrderV3 (order, market = undefined) {
//
// {
// id: '1be35109-b763-44ce-b6ea-05b6b0735c0c',
@@ -24452,7 +31687,6 @@ module.exports = class bittrex extends Exchange {
const fillQuantity = this.safeFloat (order, 'fillQuantity');
const commission = this.safeFloat (order, 'commission');
const proceeds = this.safeFloat (order, 'proceeds');
- const status = this.safeStringLower (order, 'status');
let average = undefined;
let remaining = undefined;
if (fillQuantity !== undefined) {
@@ -24467,6 +31701,11 @@ module.exports = class bittrex extends Exchange {
remaining = quantity - fillQuantity;
}
}
+ let status = this.safeStringLower (order, 'status');
+ if ((status === 'closed') && (remaining !== undefined) && (remaining > 0)) {
+ status = 'canceled';
+ }
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'timeInForce'));
return {
'id': this.safeString (order, 'id'),
'clientOrderId': undefined,
@@ -24475,8 +31714,10 @@ module.exports = class bittrex extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': direction,
'price': limit,
+ 'stopPrice': undefined,
'cost': proceeds,
'average': average,
'amount': quantity,
@@ -24492,154 +31733,32 @@ module.exports = class bittrex extends Exchange {
};
}
- parseOrderV2 (order, market = undefined) {
- //
- // {
- // "Uuid": "string (uuid)",
- // "OrderUuid": "8925d746-bc9f-4684-b1aa-e507467aaa99",
- // "Exchange": "BTC-LTC",
- // "OrderType": "string",
- // "Quantity": 100000,
- // "QuantityRemaining": 100000,
- // "Limit": 1e-8,
- // "CommissionPaid": 0,
- // "Price": 0,
- // "PricePerUnit": null,
- // "Opened": "2014-07-09T03:55:48.583",
- // "Closed": null,
- // "CancelInitiated": "boolean",
- // "ImmediateOrCancel": "boolean",
- // "IsConditional": "boolean"
- // }
- //
- let side = this.safeString2 (order, 'OrderType', 'Type');
- const isBuyOrder = (side === 'LIMIT_BUY') || (side === 'BUY');
- const isSellOrder = (side === 'LIMIT_SELL') || (side === 'SELL');
- if (isBuyOrder) {
- side = 'buy';
- }
- if (isSellOrder) {
- side = 'sell';
- }
- // We parse different fields in a very specific order.
- // Order might well be closed and then canceled.
- let status = undefined;
- if (('Opened' in order) && order['Opened']) {
- status = 'open';
- }
- if (('Closed' in order) && order['Closed']) {
- status = 'closed';
- }
- if (('CancelInitiated' in order) && order['CancelInitiated']) {
- status = 'canceled';
- }
- if (('Status' in order) && this.options['parseOrderStatus']) {
- status = this.parseOrderStatus (this.safeString (order, 'Status'));
- }
- let symbol = undefined;
- if ('Exchange' in order) {
- const marketId = this.safeString (order, 'Exchange');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = this.parseSymbol (marketId);
- }
- }
+ parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
+ if (this.options['fetchClosedOrdersFilterBySince']) {
+ return super.parseOrders (orders, market, since, limit, params);
} else {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ return super.parseOrders (orders, market, undefined, limit, params);
}
- let timestamp = undefined;
- const opened = this.safeString (order, 'Opened');
- if (opened !== undefined) {
- timestamp = this.parse8601 (opened + '+00:00');
- }
- const created = this.safeString (order, 'Created');
- if (created !== undefined) {
- timestamp = this.parse8601 (created + '+00:00');
- }
- let lastTradeTimestamp = undefined;
- const lastTimestamp = this.safeString (order, 'TimeStamp');
- if (lastTimestamp !== undefined) {
- lastTradeTimestamp = this.parse8601 (lastTimestamp + '+00:00');
- }
- const closed = this.safeString (order, 'Closed');
- if (closed !== undefined) {
- lastTradeTimestamp = this.parse8601 (closed + '+00:00');
- }
- if (timestamp === undefined) {
- timestamp = lastTradeTimestamp;
- }
- let fee = undefined;
- const feeCost = this.safeFloat2 (order, 'Commission', 'CommissionPaid');
- if (feeCost !== undefined) {
- fee = {
- 'cost': feeCost,
- };
- if (market !== undefined) {
- fee['currency'] = market['quote'];
- } else if (symbol !== undefined) {
- const currencyIds = symbol.split ('/');
- const quoteCurrencyId = currencyIds[1];
- fee['currency'] = this.safeCurrencyCode (quoteCurrencyId);
- }
- }
- let price = this.safeFloat (order, 'Limit');
- let cost = this.safeFloat (order, 'Price');
- const amount = this.safeFloat (order, 'Quantity');
- const remaining = this.safeFloat (order, 'QuantityRemaining');
- let filled = undefined;
- if (amount !== undefined && remaining !== undefined) {
- filled = amount - remaining;
- if ((status === 'closed') && (remaining > 0)) {
- status = 'canceled';
- }
- }
- if (!cost) {
- if (price && filled) {
- cost = price * filled;
- }
- }
- if (!price) {
- if (cost && filled) {
- price = cost / filled;
- }
- }
- const average = this.safeFloat (order, 'PricePerUnit');
- const id = this.safeString2 (order, 'OrderUuid', 'OrderId');
- return {
- 'info': order,
- 'id': id,
- 'clientOrderId': undefined,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'lastTradeTimestamp': lastTradeTimestamp,
- 'symbol': symbol,
- 'type': 'limit',
- 'side': side,
- 'price': price,
- 'cost': cost,
- 'average': average,
- 'amount': amount,
- 'filled': filled,
- 'remaining': remaining,
- 'status': status,
- 'fee': fee,
- 'trades': undefined,
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'CLOSED': 'closed',
+ 'OPEN': 'open',
+ 'CANCELLED': 'canceled',
+ 'CANCELED': 'canceled',
};
+ return this.safeString (statuses, status, status);
}
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
let response = undefined;
try {
- const orderIdField = this.getOrderIdField ();
- const request = {};
- request[orderIdField] = id;
- response = await this.accountGetOrder (this.extend (request, params));
+ const request = {
+ 'orderId': id,
+ };
+ response = await this.privateGetOrdersOrderId (this.extend (request, params));
} catch (e) {
if (this.last_json_response) {
const message = this.safeString (this.last_json_response, 'message');
@@ -24649,10 +31768,7 @@ module.exports = class bittrex extends Exchange {
}
throw e;
}
- if (!response['result']) {
- throw new OrderNotFound (this.id + ' order ' + id + ' not found');
- }
- return this.parseOrder (response['result']);
+ return this.parseOrder (response);
}
orderToTrade (order) {
@@ -24685,33 +31801,6 @@ module.exports = class bittrex extends Exchange {
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const orders = await this.fetchClosedOrders (symbol, since, limit, params);
- return this.ordersToTrades (orders);
- }
-
- async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const method = this.safeString (this.options, 'fetchClosedOrdersMethod', 'fetch_closed_orders_v3');
- return await this[method] (symbol, since, limit, params);
- }
-
- async fetchClosedOrdersV2 (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {};
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['market'] = market['id'];
- }
- const response = await this.accountGetOrderhistory (this.extend (request, params));
- const result = this.safeValue (response, 'result', []);
- const orders = this.parseOrders (result, market, since, limit);
- if (symbol !== undefined) {
- return this.filterBySymbol (orders, symbol);
- }
- return orders;
- }
-
- async fetchClosedOrdersV3 (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
if (limit !== undefined) {
@@ -24725,39 +31814,59 @@ module.exports = class bittrex extends Exchange {
market = this.market (symbol);
// because of this line we will have to rethink the entire v3
// in other words, markets define all the rest of the API
- // and v3 market ids are reversed in comparison to v2
+ // and v3 market ids are reversed in comparison to v1
// v3 has to be a completely separate implementation
// otherwise we will have to shuffle symbols and currencies everywhere
// which is prone to errors, as was shown here
// https://github.com/ccxt/ccxt/pull/5219#issuecomment-499646209
request['marketSymbol'] = market['base'] + '-' + market['quote'];
}
- const response = await this.v3GetOrdersClosed (this.extend (request, params));
- const orders = this.parseOrders (response, market, since, limit);
- if (symbol !== undefined) {
- return this.filterBySymbol (orders, symbol);
+ const response = await this.privateGetOrdersClosed (this.extend (request, params));
+ const orders = this.parseOrders (response, market);
+ const trades = this.ordersToTrades (orders);
+ return this.filterBySymbolSinceLimit (trades, symbol, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ if (limit !== undefined) {
+ request['pageSize'] = limit;
}
- return orders;
+ if (since !== undefined) {
+ request['startDate'] = this.ymdhms (since, 'T') + 'Z';
+ }
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ // because of this line we will have to rethink the entire v3
+ // in other words, markets define all the rest of the API
+ // and v3 market ids are reversed in comparison to v1
+ // v3 has to be a completely separate implementation
+ // otherwise we will have to shuffle symbols and currencies everywhere
+ // which is prone to errors, as was shown here
+ // https://github.com/ccxt/ccxt/pull/5219#issuecomment-499646209
+ request['marketSymbol'] = market['base'] + '-' + market['quote'];
+ }
+ const response = await this.privateGetOrdersClosed (this.extend (request, params));
+ return this.parseOrders (response, market, since, limit);
}
async fetchDepositAddress (code, params = {}) {
await this.loadMarkets ();
const currency = this.currency (code);
const request = {
- 'currency': currency['id'],
+ 'currencySymbol': currency['id'],
};
- const response = await this.accountGetDepositaddress (this.extend (request, params));
- //
- // { "success": false, "message": "ADDRESS_GENERATING", "result": null }
- //
- // { success: true,
- // message: "",
- // result: { Currency: "INCNT",
- // Address: "3PHvQt9bK21f7eVQVdJzrNPcsMzXabEA5Ha" } } }
- //
- let address = this.safeString (response['result'], 'Address');
- const message = this.safeString (response, 'message');
- if (!address || message === 'ADDRESS_GENERATING') {
+ const response = await this.privateGetAddressesCurrencySymbol (this.extend (request, params));
+ // {
+ // "status": "PROVISIONED",
+ // "currencySymbol": "BTC",
+ // "cryptoAddress": "1PhmYjnJPZH5NUwV8AUjqkeDkCBpbE2xqX"
+ // }
+ let address = this.safeString (response, 'cryptoAddress');
+ const message = this.safeString (response, 'status');
+ if (!address || message === 'REQUESTED') {
throw new AddressPending (this.id + ' the address for ' + code + ' is being generated (pending, not ready yet, retry again later)');
}
let tag = undefined;
@@ -24779,46 +31888,30 @@ module.exports = class bittrex extends Exchange {
await this.loadMarkets ();
const currency = this.currency (code);
const request = {
- 'currency': currency['id'],
+ 'currencySymbol': currency['id'],
'quantity': amount,
- 'address': address,
+ 'cryptoAddress': address,
};
if (tag !== undefined) {
- request['paymentid'] = tag;
+ request['cryptoAddressTag'] = tag;
}
- const response = await this.accountGetWithdraw (this.extend (request, params));
- const result = this.safeValue (response, 'result', {});
- const id = this.safeString (result, 'uuid');
+ const response = await this.privatePostWithdrawals (this.extend (request, params));
+ const id = this.safeString (response, 'id');
return {
'info': response,
'id': id,
};
}
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ sign (path, api = 'v3', method = 'GET', params = {}, headers = undefined, body = undefined) {
let url = this.implodeParams (this.urls['api'][api], {
'hostname': this.hostname,
}) + '/';
- if (api !== 'v2' && api !== 'v3' && api !== 'v3public') {
+ if (api === 'private') {
url += this.version + '/';
- }
- if (api === 'public') {
- url += api + '/' + method.toLowerCase () + path;
- if (Object.keys (params).length) {
- url += '?' + this.urlencode (params);
- }
- } else if (api === 'v3public') {
- url += path;
- if (Object.keys (params).length) {
- url += '?' + this.urlencode (params);
- }
- } else if (api === 'v2') {
- url += path;
- if (Object.keys (params).length) {
- url += '?' + this.urlencode (params);
- }
- } else if (api === 'v3') {
- url += path;
+ this.checkRequiredCredentials ();
+ url += this.implodeParams (path, params);
+ params = this.omit (params, this.extractParams (path));
let hashString = '';
if (method === 'POST') {
body = this.json (params);
@@ -24849,21 +31942,14 @@ module.exports = class bittrex extends Exchange {
headers['Content-Type'] = 'application/json';
}
} else {
- this.checkRequiredCredentials ();
- url += api + '/';
- if (((api === 'account') && (path !== 'withdraw')) || (path === 'openorders')) {
- url += method.toLowerCase ();
+ if (api === 'public') {
+ url += this.version + '/';
}
- const request = {
- 'apikey': this.apiKey,
- };
- const disableNonce = this.safeValue (this.options, 'disableNonce');
- if ((disableNonce === undefined) || !disableNonce) {
- request['nonce'] = this.nonce ();
+ url += this.implodeParams (path, params);
+ params = this.omit (params, this.extractParams (path));
+ if (Object.keys (params).length) {
+ url += '?' + this.urlencode (params);
}
- url += path + '?' + this.urlencode (this.extend (request, params));
- const signature = this.hmac (this.encode (url), this.encode (this.secret), 'sha512');
- headers = { 'apisign': signature };
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
@@ -24882,16 +31968,14 @@ module.exports = class bittrex extends Exchange {
const code = this.safeString (response, 'code');
if (code !== undefined) {
this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback);
- if (code !== undefined) {
- this.throwBroadlyMatchedException (this.exceptions['broad'], code, feedback);
- }
+ this.throwBroadlyMatchedException (this.exceptions['broad'], code, feedback);
}
// throw new ExchangeError (this.id + ' malformed response ' + this.json (response));
return;
}
if (typeof success === 'string') {
// bleutrade uses string instead of boolean
- success = (success === 'true') ? true : false;
+ success = (success === 'true');
}
if (!success) {
const message = this.safeString (response, 'message');
@@ -24947,24 +32031,1512 @@ module.exports = class bittrex extends Exchange {
}
}
}
+};
- async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- const response = await this.fetch2 (path, api, method, params, headers, body);
- // a workaround for APIKEY_INVALID
- if ((api === 'account') || (api === 'market')) {
- this.options['hasAlreadyAuthenticatedSuccessfully'] = true;
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],44:[function(require,module,exports){
+'use strict';
+
+// ----------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, BadSymbol, AuthenticationError, InsufficientFunds, InvalidOrder, ArgumentsRequired, OrderNotFound, InvalidAddress, BadRequest, RateLimitExceeded, PermissionDenied, ExchangeNotAvailable, AccountSuspended, OnMaintenance } = require ('./base/errors');
+const { TRUNCATE } = require ('./base/functions/number');
+
+// ----------------------------------------------------------------------------
+
+module.exports = class bitvavo extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'bitvavo',
+ 'name': 'Bitvavo',
+ 'countries': [ 'NL' ], // Netherlands
+ 'rateLimit': 500,
+ 'version': 'v2',
+ 'certified': true,
+ 'pro': true,
+ 'has': {
+ 'CORS': false,
+ 'publicAPI': true,
+ 'privateAPI': true,
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchMarkets': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '5m': '5m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '2h': '2h',
+ '4h': '4h',
+ '6h': '6h',
+ '8h': '8h',
+ '12h': '12h',
+ '1d': '1d',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/83165440-2f1cf200-a116-11ea-9046-a255d09fb2ed.jpg',
+ 'api': {
+ 'public': 'https://api.bitvavo.com',
+ 'private': 'https://api.bitvavo.com',
+ },
+ 'www': 'https://bitvavo.com/',
+ 'doc': 'https://docs.bitvavo.com/',
+ 'fees': 'https://bitvavo.com/en/fees',
+ 'referral': 'https://bitvavo.com/?a=24F34952F7',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'time',
+ 'markets',
+ 'assets',
+ '{market}/book',
+ '{market}/trades',
+ '{market}/candles',
+ 'ticker/price',
+ 'ticker/book',
+ 'ticker/24h',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'order',
+ 'orders',
+ 'ordersOpen',
+ 'trades',
+ 'balance',
+ 'deposit',
+ 'depositHistory',
+ 'withdrawalHistory',
+ ],
+ 'post': [
+ 'order',
+ 'withdrawal',
+ ],
+ 'put': [
+ 'order',
+ ],
+ 'delete': [
+ 'order',
+ 'orders',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.25 / 100,
+ 'maker': 0.20 / 100,
+ 'tiers': {
+ 'taker': [
+ [ 0, 0.0025 ],
+ [ 50000, 0.0024 ],
+ [ 100000, 0.0022 ],
+ [ 250000, 0.0020 ],
+ [ 500000, 0.0018 ],
+ [ 1000000, 0.0016 ],
+ [ 2500000, 0.0014 ],
+ [ 5000000, 0.0012 ],
+ [ 10000000, 0.0010 ],
+ ],
+ 'maker': [
+ [ 0, 0.0020 ],
+ [ 50000, 0.0015 ],
+ [ 100000, 0.0010 ],
+ [ 250000, 0.0006 ],
+ [ 500000, 0.0003 ],
+ [ 1000000, 0.0001 ],
+ [ 2500000, -0.0001 ],
+ [ 5000000, -0.0003 ],
+ [ 10000000, -0.0005 ],
+ ],
+ },
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ },
+ 'exceptions': {
+ 'exact': {
+ '101': ExchangeError, // Unknown error. Operation may or may not have succeeded.
+ '102': BadRequest, // Invalid JSON.
+ '103': RateLimitExceeded, // You have been rate limited. Please observe the Bitvavo-Ratelimit-AllowAt header to see when you can send requests again. Failure to respect this limit will result in an IP ban. The default value is 1000 weighted requests per minute. Please contact support if you wish to increase this limit.
+ '104': RateLimitExceeded, // You have been rate limited by the number of new orders. The default value is 100 new orders per second or 100.000 new orders per day. Please update existing orders instead of cancelling and creating orders. Please contact support if you wish to increase this limit.
+ '105': PermissionDenied, // Your IP or API key has been banned for not respecting the rate limit. The ban expires at ${expiryInMs}.
+ '107': ExchangeNotAvailable, // The matching engine is overloaded. Please wait 500ms and resubmit your order.
+ '108': ExchangeNotAvailable, // The matching engine could not process your order in time. Please consider increasing the access window or resubmit your order.
+ '109': ExchangeNotAvailable, // The matching engine did not respond in time. Operation may or may not have succeeded.
+ '110': BadRequest, // Invalid endpoint. Please check url and HTTP method.
+ '200': BadRequest, // ${param} url parameter is not supported. Please note that parameters are case-sensitive and use body parameters for PUT and POST requests.
+ '201': BadRequest, // ${param} body parameter is not supported. Please note that parameters are case-sensitive and use url parameters for GET and DELETE requests.
+ '202': BadRequest, // ${param} order parameter is not supported. Please note that certain parameters are only allowed for market or limit orders.
+ '203': BadSymbol, // {"errorCode":203,"error":"symbol parameter is required."}
+ '204': BadRequest, // ${param} parameter is not supported.
+ '205': BadRequest, // ${param} parameter is invalid.
+ '206': BadRequest, // Use either ${paramA} or ${paramB}. The usage of both parameters at the same time is not supported.
+ '210': InvalidOrder, // Amount exceeds the maximum allowed amount (1000000000).
+ '211': InvalidOrder, // Price exceeds the maximum allowed amount (100000000000).
+ '212': InvalidOrder, // Amount is below the minimum allowed amount for this asset.
+ '213': InvalidOrder, // Price is below the minimum allowed amount (0.000000000000001).
+ '214': InvalidOrder, // Price is too detailed
+ '215': InvalidOrder, // Price is too detailed. A maximum of 15 digits behind the decimal point are allowed.
+ '216': InsufficientFunds, // {"errorCode":216,"error":"You do not have sufficient balance to complete this operation."}
+ '217': InvalidOrder, // {"errorCode":217,"error":"Minimum order size in quote currency is 5 EUR or 0.001 BTC."}
+ '230': ExchangeError, // The order is rejected by the matching engine.
+ '231': ExchangeError, // The order is rejected by the matching engine. TimeInForce must be GTC when markets are paused.
+ '232': BadRequest, // You must change at least one of amount, amountRemaining, price, timeInForce, selfTradePrevention or postOnly.
+ '233': InvalidOrder, // {"errorCode":233,"error":"Order must be active (status new or partiallyFilled) to allow updating/cancelling."}
+ '234': InvalidOrder, // Market orders cannot be updated.
+ '235': ExchangeError, // You can only have 100 open orders on each book.
+ '236': BadRequest, // You can only update amount or amountRemaining, not both.
+ '240': OrderNotFound, // {"errorCode":240,"error":"No order found. Please be aware that simultaneously updating the same order may return this error."}
+ '300': AuthenticationError, // Authentication is required for this endpoint.
+ '301': AuthenticationError, // {"errorCode":301,"error":"API Key must be of length 64."}
+ '302': AuthenticationError, // Timestamp is invalid. This must be a timestamp in ms. See Bitvavo-Access-Timestamp header or timestamp parameter for websocket.
+ '303': AuthenticationError, // Window must be between 100 and 60000 ms.
+ '304': AuthenticationError, // Request was not received within acceptable window (default 30s, or custom with Bitvavo-Access-Window header) of Bitvavo-Access-Timestamp header (or timestamp parameter for websocket).
+ // '304': AuthenticationError, // Authentication is required for this endpoint.
+ '305': AuthenticationError, // {"errorCode":305,"error":"No active API key found."}
+ '306': AuthenticationError, // No active API key found. Please ensure that you have confirmed the API key by e-mail.
+ '307': PermissionDenied, // This key does not allow access from this IP.
+ '308': AuthenticationError, // {"errorCode":308,"error":"The signature length is invalid (HMAC-SHA256 should return a 64 length hexadecimal string)."}
+ '309': AuthenticationError, // {"errorCode":309,"error":"The signature is invalid."}
+ '310': PermissionDenied, // This key does not allow trading actions.
+ '311': PermissionDenied, // This key does not allow showing account information.
+ '312': PermissionDenied, // This key does not allow withdrawal of funds.
+ '315': BadRequest, // Websocket connections may not be used in a browser. Please use REST requests for this.
+ '317': AccountSuspended, // This account is locked. Please contact support.
+ '400': ExchangeError, // Unknown error. Please contact support with a copy of your request.
+ '401': ExchangeError, // Deposits for this asset are not available at this time.
+ '402': PermissionDenied, // You need to verify your identitiy before you can deposit and withdraw digital assets.
+ '403': PermissionDenied, // You need to verify your phone number before you can deposit and withdraw digital assets.
+ '404': OnMaintenance, // Could not complete this operation, because our node cannot be reached. Possibly under maintenance.
+ '405': ExchangeError, // You cannot withdraw digital assets during a cooldown period. This is the result of newly added bank accounts.
+ '406': BadRequest, // {"errorCode":406,"error":"Your withdrawal is too small."}
+ '407': ExchangeError, // Internal transfer is not possible.
+ '408': InsufficientFunds, // {"errorCode":408,"error":"You do not have sufficient balance to complete this operation."}
+ '409': InvalidAddress, // {"errorCode":409,"error":"This is not a verified bank account."}
+ '410': ExchangeError, // Withdrawals for this asset are not available at this time.
+ '411': BadRequest, // You can not transfer assets to yourself.
+ '412': InvalidAddress, // {"errorCode":412,"error":"eth_address_invalid."}
+ '413': InvalidAddress, // This address violates the whitelist.
+ '414': ExchangeError, // You cannot withdraw assets within 2 minutes of logging in.
+ },
+ 'broad': {
+ 'start parameter is invalid': BadRequest, // {"errorCode":205,"error":"start parameter is invalid."}
+ 'symbol parameter is invalid': BadSymbol, // {"errorCode":205,"error":"symbol parameter is invalid."}
+ 'amount parameter is invalid': InvalidOrder, // {"errorCode":205,"error":"amount parameter is invalid."}
+ 'orderId parameter is invalid': InvalidOrder, // {"errorCode":205,"error":"orderId parameter is invalid."}
+ },
+ },
+ 'options': {
+ 'BITVAVO-ACCESS-WINDOW': 10000, // default 10 sec
+ 'fetchCurrencies': {
+ 'expires': 1000, // 1 second
+ },
+ },
+ 'commonCurrencies': {
+ 'MIOTA': 'IOTA', // https://github.com/ccxt/ccxt/issues/7487
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // { "time": 1590379519148 }
+ //
+ return this.safeInteger (response, 'time');
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetMarkets (params);
+ const currencies = await this.fetchCurrenciesFromCache (params);
+ const currenciesById = this.indexBy (currencies, 'symbol');
+ //
+ // [
+ // {
+ // "market":"ADA-BTC",
+ // "status":"trading", // "trading" "halted" "auction"
+ // "base":"ADA",
+ // "quote":"BTC",
+ // "pricePrecision":5,
+ // "minOrderInBaseAsset":"100",
+ // "minOrderInQuoteAsset":"0.001",
+ // "orderTypes": [ "market", "limit" ]
+ // }
+ // ]
+ //
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ const id = this.safeString (market, 'market');
+ const baseId = this.safeString (market, 'base');
+ const quoteId = this.safeString (market, 'quote');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const status = this.safeString (market, 'status');
+ const active = (status === 'trading');
+ const baseCurrency = this.safeValue (currenciesById, baseId);
+ let amountPrecision = undefined;
+ if (baseCurrency !== undefined) {
+ amountPrecision = this.safeInteger (baseCurrency, 'decimals', 8);
+ }
+ const precision = {
+ 'price': this.safeInteger (market, 'pricePrecision'),
+ 'amount': amountPrecision,
+ };
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'info': market,
+ 'active': active,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': this.safeFloat (market, 'minOrderInBaseAsset'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': this.safeFloat (market, 'minOrderInQuoteAsset'),
+ 'max': undefined,
+ },
+ },
+ });
+ }
+ return result;
+ }
+
+ async fetchCurrenciesFromCache (params = {}) {
+ // this method is now redundant
+ // currencies are now fetched before markets
+ const options = this.safeValue (this.options, 'fetchCurrencies', {});
+ const timestamp = this.safeInteger (options, 'timestamp');
+ const expires = this.safeInteger (options, 'expires', 1000);
+ const now = this.milliseconds ();
+ if ((timestamp === undefined) || ((now - timestamp) > expires)) {
+ const response = await this.publicGetAssets (params);
+ this.options['fetchCurrencies'] = this.extend (options, {
+ 'response': response,
+ 'timestamp': now,
+ });
+ }
+ return this.safeValue (this.options['fetchCurrencies'], 'response');
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.fetchCurrenciesFromCache (params);
+ //
+ // [
+ // {
+ // "symbol":"ADA",
+ // "name":"Cardano",
+ // "decimals":6,
+ // "depositFee":"0",
+ // "depositConfirmations":15,
+ // "depositStatus":"OK", // "OK", "MAINTENANCE", "DELISTED"
+ // "withdrawalFee":"0.2",
+ // "withdrawalMinAmount":"0.2",
+ // "withdrawalStatus":"OK", // "OK", "MAINTENANCE", "DELISTED"
+ // "networks": [ "Mainnet" ], // "ETH", "NEO", "ONT", "SEPA", "VET"
+ // "message":"",
+ // },
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const currency = response[i];
+ const id = this.safeString (currency, 'symbol');
+ const code = this.safeCurrencyCode (id);
+ const depositStatus = this.safeValue (currency, 'depositStatus');
+ const deposit = (depositStatus === 'OK');
+ const withdrawalStatus = this.safeValue (currency, 'withdrawalStatus');
+ const withdrawal = (withdrawalStatus === 'OK');
+ const active = deposit && withdrawal;
+ const name = this.safeString (currency, 'name');
+ const precision = this.safeInteger (currency, 'decimals', 8);
+ result[code] = {
+ 'id': id,
+ 'info': currency,
+ 'code': code,
+ 'name': name,
+ 'active': active,
+ 'fee': this.safeFloat (currency, 'withdrawalFee'),
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (currency, 'withdrawalMinAmount'),
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ };
+ const response = await this.publicGetTicker24h (this.extend (request, params));
+ //
+ // {
+ // "market":"ETH-BTC",
+ // "open":"0.022578",
+ // "high":"0.023019",
+ // "low":"0.022573",
+ // "last":"0.023019",
+ // "volume":"25.16366324",
+ // "volumeQuote":"0.57333305",
+ // "bid":"0.023039",
+ // "bidSize":"0.53500578",
+ // "ask":"0.023041",
+ // "askSize":"0.47859202",
+ // "timestamp":1590381666900
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker
+ //
+ // {
+ // "market":"ETH-BTC",
+ // "open":"0.022578",
+ // "high":"0.023019",
+ // "low":"0.022573",
+ // "last":"0.023019",
+ // "volume":"25.16366324",
+ // "volumeQuote":"0.57333305",
+ // "bid":"0.023039",
+ // "bidSize":"0.53500578",
+ // "ask":"0.023041",
+ // "askSize":"0.47859202",
+ // "timestamp":1590381666900
+ // }
+ //
+ const marketId = this.safeString (ticker, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const timestamp = this.safeInteger (ticker, 'timestamp');
+ const last = this.safeFloat (ticker, 'last');
+ const baseVolume = this.safeFloat (ticker, 'volume');
+ const quoteVolume = this.safeFloat (ticker, 'volumeQuote');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ let change = undefined;
+ let percentage = undefined;
+ let average = undefined;
+ const open = this.safeFloat (ticker, 'open');
+ if ((open !== undefined) && (last !== undefined)) {
+ change = last - open;
+ if (open > 0) {
+ percentage = change / open * 100;
+ }
+ average = this.sum (open, last) / 2;
+ }
+ const result = {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': this.safeFloat (ticker, 'bid'),
+ 'bidVolume': this.safeFloat (ticker, 'bidSize'),
+ 'ask': this.safeFloat (ticker, 'ask'),
+ 'askVolume': this.safeFloat (ticker, 'askSize'),
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined, // previous day close
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ return result;
+ }
+
+ parseTickers (tickers, symbols = undefined) {
+ const result = [];
+ for (let i = 0; i < tickers.length; i++) {
+ result.push (this.parseTicker (tickers[i]));
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetTicker24h (params);
+ //
+ // [
+ // {
+ // "market":"ADA-BTC",
+ // "open":"0.0000059595",
+ // "high":"0.0000059765",
+ // "low":"0.0000059595",
+ // "last":"0.0000059765",
+ // "volume":"2923.172",
+ // "volumeQuote":"0.01743483",
+ // "bid":"0.0000059515",
+ // "bidSize":"1117.630919",
+ // "ask":"0.0000059585",
+ // "askSize":"809.999739",
+ // "timestamp":1590382266324
+ // }
+ // ]
+ //
+ return this.parseTickers (response, symbols);
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ // 'limit': 500, // default 500, max 1000
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ // 'tradeIdFrom': '57b1159b-6bf5-4cde-9e2c-6bd6a5678baf',
+ // 'tradeIdTo': '57b1159b-6bf5-4cde-9e2c-6bd6a5678baf',
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ const response = await this.publicGetMarketTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id":"94154c98-6e8b-4e33-92a8-74e33fc05650",
+ // "timestamp":1590382761859,
+ // "amount":"0.06026079",
+ // "price":"8095.3",
+ // "side":"buy"
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // {
+ // "id":"94154c98-6e8b-4e33-92a8-74e33fc05650",
+ // "timestamp":1590382761859,
+ // "amount":"0.06026079",
+ // "price":"8095.3",
+ // "side":"buy"
+ // }
+ //
+ // createOrder, fetchOpenOrders, fetchOrders, editOrder (private)
+ //
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ //
+ // fetchMyTrades (private)
+ //
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "timestamp":1590505649245,
+ // "market":"ETH-EUR",
+ // "side":"sell",
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ //
+ // watchMyTrades (private)
+ //
+ // {
+ // event: 'fill',
+ // timestamp: 1590964470132,
+ // market: 'ETH-EUR',
+ // orderId: '85d082e1-eda4-4209-9580-248281a29a9a',
+ // fillId: '861d2da5-aa93-475c-8d9a-dce431bd4211',
+ // side: 'sell',
+ // amount: '0.1',
+ // price: '211.46',
+ // taker: true,
+ // fee: '0.056',
+ // feeCurrency: 'EUR'
+ // }
+ //
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'amount');
+ let cost = undefined;
+ if ((price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ const timestamp = this.safeInteger (trade, 'timestamp');
+ const side = this.safeString (trade, 'side');
+ const id = this.safeString2 (trade, 'id', 'fillId');
+ const marketId = this.safeInteger (trade, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const taker = this.safeValue (trade, 'taker');
+ let takerOrMaker = undefined;
+ if (taker !== undefined) {
+ takerOrMaker = taker ? 'taker' : 'maker';
+ }
+ const feeCost = this.safeFloat (trade, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (trade, 'feeCurrency');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ const orderId = this.safeString (trade, 'orderId');
+ return {
+ 'info': trade,
+ 'id': id,
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'order': orderId,
+ 'type': undefined,
+ 'side': side,
+ 'takerOrMaker': takerOrMaker,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'market': this.marketId (symbol),
+ };
+ if (limit !== undefined) {
+ request['depth'] = limit;
+ }
+ const response = await this.publicGetMarketBook (this.extend (request, params));
+ //
+ // {
+ // "market":"BTC-EUR",
+ // "nonce":35883831,
+ // "bids":[
+ // ["8097.4","0.6229099"],
+ // ["8097.2","0.64151283"],
+ // ["8097.1","0.24966294"],
+ // ],
+ // "asks":[
+ // ["8097.5","1.36916911"],
+ // ["8098.8","0.33462248"],
+ // ["8099.3","1.12908646"],
+ // ]
+ // }
+ //
+ const orderbook = this.parseOrderBook (response);
+ orderbook['nonce'] = this.safeInteger (response, 'nonce');
+ return orderbook;
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1590383700000,
+ // "8088.5",
+ // "8088.5",
+ // "8088.5",
+ // "8088.5",
+ // "0.04788623"
+ // ]
+ //
+ return [
+ this.safeInteger (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ 'interval': this.timeframes[timeframe],
+ // 'limit': 1440, // default 1440, max 1440
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 1440, max 1440
+ }
+ const response = await this.publicGetMarketCandles (this.extend (request, params));
+ //
+ // [
+ // [1590383700000,"8088.5","8088.5","8088.5","8088.5","0.04788623"],
+ // [1590383580000,"8091.3","8091.5","8091.3","8091.5","0.04931221"],
+ // [1590383520000,"8090.3","8092.7","8090.3","8092.5","0.04001286"],
+ // ]
+ //
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetBalance (params);
+ //
+ // [
+ // {
+ // "symbol": "BTC",
+ // "available": "1.57593193",
+ // "inOrder": "0.74832374"
+ // }
+ // ]
+ //
+ const result = { 'info': response };
+ for (let i = 0; i < response.length; i++) {
+ const balance = response[i];
+ const currencyId = this.safeString (balance, 'symbol');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = {
+ 'free': this.safeFloat (balance, 'available'),
+ 'used': this.safeFloat (balance, 'inOrder'),
+ };
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'symbol': currency['id'],
+ };
+ const response = await this.privateGetDeposit (this.extend (request, params));
+ //
+ // {
+ // "address": "0x449889e3234514c45d57f7c5a571feba0c7ad567",
+ // "paymentId": "10002653"
+ // }
+ //
+ const address = this.safeString (response, 'address');
+ const tag = this.safeString (response, 'paymentId');
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': response,
+ };
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ 'side': side,
+ 'orderType': type,
+ // 'amount': this.amountToPrecision (symbol, amount),
+ // 'price': this.priceToPrecision (symbol, price),
+ // 'amountQuote': this.costToPrecision (symbol, cost),
+ // 'timeInForce': 'GTC', // "GTC" "IOC" "FOK"
+ // 'selfTradePrevention': "decrementAndCancel", // "decrementAndCancel" "cancelOldest" "cancelNewest" "cancelBoth"
+ // 'postOnly': false,
+ // 'disableMarketProtection': false, // don't cancel if the next fill price is 10% worse than the best fill price
+ // 'responseRequired': true, // false is faster
+ };
+ if (type === 'market') {
+ let cost = undefined;
+ if (price !== undefined) {
+ cost = amount * price;
+ } else {
+ cost = this.safeFloat2 (params, 'cost', 'amountQuote');
+ }
+ if (cost !== undefined) {
+ const precision = market['precision']['price'];
+ request['amountQuote'] = this.decimalToPrecision (cost, TRUNCATE, precision, this.precisionMode);
+ } else {
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ }
+ params = this.omit (params, [ 'cost', 'amountQuote' ]);
+ } else if (type === 'limit') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ }
+ const response = await this.privatePostOrder (this.extend (request, params));
+ //
+ // {
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "market":"ETH-EUR",
+ // "created":1590505649241,
+ // "updated":1590505649241,
+ // "status":"filled",
+ // "side":"sell",
+ // "orderType":"market",
+ // "amount":"0.249825",
+ // "amountRemaining":"0",
+ // "onHold":"0",
+ // "onHoldCurrency":"ETH",
+ // "filledAmount":"0.249825",
+ // "filledAmountQuote":"45.84038925",
+ // "feePaid":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "fills":[
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ],
+ // "selfTradePrevention":"decrementAndCancel",
+ // "visible":false,
+ // "disableMarketProtection":false
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ let request = {};
+ const amountRemaining = this.safeFloat (params, 'amountRemaining');
+ params = this.omit (params, 'amountRemaining');
+ if (price !== undefined) {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ if (amount !== undefined) {
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ }
+ if (amountRemaining !== undefined) {
+ request['amountRemaining'] = this.amountToPrecision (symbol, amountRemaining);
+ }
+ request = this.extend (request, params);
+ if (Object.keys (request).length) {
+ request['orderId'] = id;
+ request['market'] = market['id'];
+ const response = await this.privatePutOrder (this.extend (request, params));
+ return this.parseOrder (response, market);
+ } else {
+ throw new ArgumentsRequired (this.id + ' editOrder requires an amount argument, or a price argument, or non-empty params');
+ }
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'orderId': id,
+ 'market': market['id'],
+ };
+ const response = await this.privateDeleteOrder (this.extend (request, params));
+ //
+ // {
+ // "orderId": "2e7ce7fc-44e2-4d80-a4a7-d079c4750b61"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market'] = market['id'];
+ }
+ const response = await this.privateDeleteOrders (this.extend (request, params));
+ //
+ // [
+ // {
+ // "orderId": "1be6d0df-d5dc-4b53-a250-3376f3b393e6"
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'orderId': id,
+ 'market': market['id'],
+ };
+ const response = await this.privateGetOrder (this.extend (request, params));
+ //
+ // {
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "market":"ETH-EUR",
+ // "created":1590505649241,
+ // "updated":1590505649241,
+ // "status":"filled",
+ // "side":"sell",
+ // "orderType":"market",
+ // "amount":"0.249825",
+ // "amountRemaining":"0",
+ // "onHold":"0",
+ // "onHoldCurrency":"ETH",
+ // "filledAmount":"0.249825",
+ // "filledAmountQuote":"45.84038925",
+ // "feePaid":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "fills":[
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ],
+ // "selfTradePrevention":"decrementAndCancel",
+ // "visible":false,
+ // "disableMarketProtection":false
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ // 'limit': 500,
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ // 'orderIdFrom': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ // 'orderIdTo': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 500, max 1000
+ }
+ const response = await this.privateGetOrders (this.extend (request, params));
+ //
+ // [
+ // {
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "market":"ETH-EUR",
+ // "created":1590505649241,
+ // "updated":1590505649241,
+ // "status":"filled",
+ // "side":"sell",
+ // "orderType":"market",
+ // "amount":"0.249825",
+ // "amountRemaining":"0",
+ // "onHold":"0",
+ // "onHoldCurrency":"ETH",
+ // "filledAmount":"0.249825",
+ // "filledAmountQuote":"45.84038925",
+ // "feePaid":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "fills":[
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ],
+ // "selfTradePrevention":"decrementAndCancel",
+ // "visible":false,
+ // "disableMarketProtection":false
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'market': market['id'],
+ // 'limit': 500,
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ // 'orderIdFrom': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ // 'orderIdTo': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 500, max 1000
+ }
+ const response = await this.privateGetOrdersOpen (this.extend (request, params));
+ //
+ // [
+ // {
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "market":"ETH-EUR",
+ // "created":1590505649241,
+ // "updated":1590505649241,
+ // "status":"filled",
+ // "side":"sell",
+ // "orderType":"market",
+ // "amount":"0.249825",
+ // "amountRemaining":"0",
+ // "onHold":"0",
+ // "onHoldCurrency":"ETH",
+ // "filledAmount":"0.249825",
+ // "filledAmountQuote":"45.84038925",
+ // "feePaid":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "fills":[
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ],
+ // "selfTradePrevention":"decrementAndCancel",
+ // "visible":false,
+ // "disableMarketProtection":false
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'new': 'open',
+ 'canceled': 'canceled',
+ 'canceledAuction': 'canceled',
+ 'canceledSelfTradePrevention': 'canceled',
+ 'canceledIOC': 'canceled',
+ 'canceledFOK': 'canceled',
+ 'canceledMarketProtection': 'canceled',
+ 'canceledPostOnly': 'canceled',
+ 'filled': 'closed',
+ 'partiallyFilled': 'open',
+ 'expired': 'canceled',
+ 'rejected': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // cancelOrder, cancelAllOrders
+ //
+ // {
+ // "orderId": "2e7ce7fc-44e2-4d80-a4a7-d079c4750b61"
+ // }
+ //
+ // createOrder, fetchOrder, fetchOpenOrders, fetchOrders, editOrder
+ //
+ // {
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "market":"ETH-EUR",
+ // "created":1590505649241,
+ // "updated":1590505649241,
+ // "status":"filled",
+ // "side":"sell",
+ // "orderType":"market",
+ // "amount":"0.249825",
+ // "amountRemaining":"0",
+ // "price": "183.49", // limit orders only
+ // "onHold":"0",
+ // "onHoldCurrency":"ETH",
+ // "filledAmount":"0.249825",
+ // "filledAmountQuote":"45.84038925",
+ // "feePaid":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "fills":[
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ],
+ // "selfTradePrevention":"decrementAndCancel",
+ // "visible":false,
+ // "disableMarketProtection":false
+ // "timeInForce": "GTC",
+ // "postOnly": true,
+ // }
+ //
+ const id = this.safeString (order, 'orderId');
+ const timestamp = this.safeInteger (order, 'created');
+ const marketId = this.safeString (order, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const side = this.safeString (order, 'side');
+ const type = this.safeString (order, 'orderType');
+ const price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'amount');
+ let remaining = this.safeFloat (order, 'amountRemaining');
+ let filled = this.safeFloat (order, 'filledAmount');
+ const remainingCost = this.safeFloat (order, 'remainingCost');
+ if ((remainingCost !== undefined) && (remainingCost === 0.0)) {
+ remaining = 0;
+ }
+ if ((amount !== undefined) && (remaining !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ const cost = this.safeFloat (order, 'filledAmountQuote');
+ let average = undefined;
+ if (cost !== undefined) {
+ if (filled) {
+ average = cost / filled;
+ }
+ }
+ let fee = undefined;
+ const feeCost = this.safeFloat (order, 'feePaid');
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (order, 'feeCurrency');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ let lastTradeTimestamp = undefined;
+ const rawTrades = this.safeValue (order, 'fills');
+ let trades = undefined;
+ if (rawTrades !== undefined) {
+ trades = this.parseTrades (rawTrades, market, undefined, undefined, {
+ 'symbol': symbol,
+ 'order': id,
+ 'side': side,
+ });
+ const numTrades = trades.length;
+ if (numTrades > 0) {
+ const lastTrade = this.safeValue (trades, numTrades - 1);
+ lastTradeTimestamp = lastTrade['timestamp'];
+ }
+ }
+ const timeInForce = this.safeString (order, 'timeInForce');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': timeInForce,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': trades,
+ };
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ // 'limit': 500,
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ // 'tradeIdFrom': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ // 'tradeIdTo': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 500, max 1000
+ }
+ const response = await this.privateGetTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "timestamp":1590505649245,
+ // "market":"ETH-EUR",
+ // "side":"sell",
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'symbol': currency['id'],
+ 'amount': this.currencyToPrecision (code, amount),
+ 'address': address, // address or IBAN
+ // 'internal': false, // transfer to another Bitvavo user address, no fees
+ // 'addWithdrawalFee': false, // true = add the fee on top, otherwise the fee is subtracted from the amount
+ };
+ if (tag !== undefined) {
+ request['paymentId'] = tag;
+ }
+ const response = await this.privatePostWithdrawal (this.extend (request, params));
+ //
+ // {
+ // "success": true,
+ // "symbol": "BTC",
+ // "amount": "1.5"
+ // }
+ //
+ return this.parseTransaction (response, currency);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'symbol': currency['id'],
+ // 'limit': 500, // default 500, max 1000
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['symbol'] = currency['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 500, max 1000
+ }
+ const response = await this.privateGetWithdrawalHistory (this.extend (request, params));
+ //
+ // [
+ // {
+ // "timestamp":1590531212000,
+ // "symbol":"ETH",
+ // "amount":"0.091",
+ // "fee":"0.009",
+ // "status":"awaiting_bitvavo_inspection",
+ // "address":"0xe42b309f1eE9F0cbf7f54CcF3bc2159eBfA6735b",
+ // "paymentId": "10002653",
+ // "txId": "927b3ea50c5bb52c6854152d305dfa1e27fc01d10464cf10825d96d69d235eb3",
+ // }
+ // ]
+ //
+ return this.parseTransactions (response, currency, since, limit);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'symbol': currency['id'],
+ // 'limit': 500, // default 500, max 1000
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['symbol'] = currency['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 500, max 1000
+ }
+ const response = await this.privateGetDepositHistory (this.extend (request, params));
+ //
+ // [
+ // {
+ // "timestamp":1590492401000,
+ // "symbol":"ETH",
+ // "amount":"0.249825",
+ // "fee":"0",
+ // "status":"completed",
+ // "txId":"0x5167b473fd37811f9ef22364c3d54726a859ef9d98934b3a1e11d7baa8d2c2e2"
+ // }
+ // ]
+ //
+ return this.parseTransactions (response, currency, since, limit);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'awaiting_processing': 'pending',
+ 'awaiting_email_confirmation': 'pending',
+ 'awaiting_bitvavo_inspection': 'pending',
+ 'approved': 'pending',
+ 'sending': 'pending',
+ 'in_mempool': 'pending',
+ 'processed': 'pending',
+ 'completed': 'ok',
+ 'canceled': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // withdraw
+ //
+ // {
+ // "success": true,
+ // "symbol": "BTC",
+ // "amount": "1.5"
+ // }
+ //
+ // fetchWithdrawals
+ //
+ // {
+ // "timestamp": 1542967486256,
+ // "symbol": "BTC",
+ // "amount": "0.99994",
+ // "address": "BitcoinAddress",
+ // "paymentId": "10002653",
+ // "txId": "927b3ea50c5bb52c6854152d305dfa1e27fc01d10464cf10825d96d69d235eb3",
+ // "fee": "0.00006",
+ // "status": "awaiting_processing"
+ // }
+ //
+ // fetchDeposits
+ //
+ // {
+ // "timestamp":1590492401000,
+ // "symbol":"ETH",
+ // "amount":"0.249825",
+ // "fee":"0",
+ // "status":"completed",
+ // "txId":"0x5167b473fd37811f9ef22364c3d54726a859ef9d98934b3a1e11d7baa8d2c2e2"
+ // }
+ //
+ const id = undefined;
+ const timestamp = this.safeInteger (transaction, 'timestamp');
+ const currencyId = this.safeString (transaction, 'symbol');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const amount = this.safeFloat (transaction, 'amount');
+ const address = this.safeString (transaction, 'address');
+ const txid = this.safeString (transaction, 'txId');
+ let fee = undefined;
+ const feeCost = this.safeFloat (transaction, 'fee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': code,
+ };
+ }
+ let type = undefined;
+ if ('success' in transaction) {
+ type = 'withdrawal';
+ } else {
+ type = (status === undefined) ? 'deposit' : 'withdrawal';
+ }
+ const tag = this.safeString (transaction, 'paymentId');
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'addressFrom': undefined,
+ 'address': address,
+ 'addressTo': address,
+ 'tagFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'type': type,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': undefined,
+ 'fee': fee,
+ };
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const query = this.omit (params, this.extractParams (path));
+ let url = '/' + this.version + '/' + this.implodeParams (path, params);
+ const getOrDelete = (method === 'GET') || (method === 'DELETE');
+ if (getOrDelete) {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ }
+ if (api === 'private') {
+ this.checkRequiredCredentials ();
+ let payload = '';
+ if (!getOrDelete) {
+ if (Object.keys (query).length) {
+ body = this.json (query);
+ payload = body;
+ }
+ }
+ const timestamp = this.milliseconds ().toString ();
+ const auth = timestamp + method + url + payload;
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret));
+ const accessWindow = this.safeString (this.options, 'BITVAVO-ACCESS-WINDOW', '10000');
+ headers = {
+ 'BITVAVO-ACCESS-KEY': this.apiKey,
+ 'BITVAVO-ACCESS-SIGNATURE': signature,
+ 'BITVAVO-ACCESS-TIMESTAMP': timestamp,
+ 'BITVAVO-ACCESS-WINDOW': accessWindow,
+ };
+ if (!getOrDelete) {
+ headers['Content-Type'] = 'application/json';
+ }
+ }
+ url = this.urls['api'][api] + url;
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ //
+ // {"errorCode":308,"error":"The signature length is invalid (HMAC-SHA256 should return a 64 length hexadecimal string)."}
+ // {"errorCode":203,"error":"symbol parameter is required."}
+ // {"errorCode":205,"error":"symbol parameter is invalid."}
+ //
+ const errorCode = this.safeString (response, 'errorCode');
+ const error = this.safeString (response, 'error');
+ if (errorCode !== undefined) {
+ const feedback = this.id + ' ' + body;
+ this.throwBroadlyMatchedException (this.exceptions['broad'], error, feedback);
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ throw new ExchangeError (feedback); // unknown message
}
- return response;
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],44:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],45:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, PermissionDenied, InvalidOrder, AuthenticationError, InsufficientFunds, OrderNotFound, DDoSProtection } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, PermissionDenied, InvalidOrder, AuthenticationError, InsufficientFunds, OrderNotFound, DDoSProtection, OnMaintenance, RateLimitExceeded } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -24978,16 +33550,26 @@ module.exports = class bitz extends Exchange {
'version': 'v2',
'userAgent': this.userAgents['chrome'],
'has': {
- 'fetchTickers': true,
+ 'cancelOrder': true,
+ 'cancelOrders': true,
+ 'createOrder': true,
+ 'createMarketOrder': false,
+ 'fetchBalance': true,
+ 'fetchDeposits': true,
+ 'fetchClosedOrders': true,
+ 'fetchMarkets': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'fetchOrders': true,
'fetchOrder': true,
- 'createMarketOrder': false,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTransactions': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1min',
@@ -25003,7 +33585,7 @@ module.exports = class bitz extends Exchange {
},
'hostname': 'apiv2.bitz.com',
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/35862606-4f554f14-0b5d-11e8-957d-35058c504b6f.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87443304-fec5e000-c5fd-11ea-98f8-ba8e67f7eaff.jpg',
'api': {
'market': 'https://{hostname}',
'trade': 'https://{hostname}',
@@ -25023,6 +33605,7 @@ module.exports = class bitz extends Exchange {
'tickerall',
'kline',
'symbolList',
+ 'getServerTime',
'currencyRate',
'currencyCoinRate',
'coinRate',
@@ -25033,6 +33616,7 @@ module.exports = class bitz extends Exchange {
'addEntrustSheet',
'cancelEntrustSheet',
'cancelAllEntrustSheet',
+ 'coinOut', // withdraw
'getUserHistoryEntrustSheet', // closed orders
'getUserNowEntrustSheet', // open orders
'getEntrustSheetInfo', // order
@@ -25137,7 +33721,9 @@ module.exports = class bitz extends Exchange {
'-109': AuthenticationError, // Invalid scretKey
'-110': DDoSProtection, // The number of access requests exceeded
'-111': PermissionDenied, // Current IP is not in the range of trusted IP
- '-112': ExchangeNotAvailable, // Service is under maintenance
+ '-112': OnMaintenance, // Service is under maintenance
+ '-114': RateLimitExceeded, // The number of daily requests has reached the limit
+ '-117': AuthenticationError, // The apikey expires
'-100015': AuthenticationError, // Trade password error
'-100044': ExchangeError, // Fail to request data
'-100101': ExchangeError, // Invalid symbol
@@ -25311,14 +33897,8 @@ module.exports = class bitz extends Exchange {
// krw: "318655.82" }
//
const timestamp = undefined;
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (ticker, 'symbol');
- market = this.safeValue (this.markets_by_id, marketId);
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (ticker, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
const last = this.safeFloat (ticker, 'now');
const open = this.safeFloat (ticker, 'open');
let change = undefined;
@@ -25471,7 +34051,22 @@ module.exports = class bitz extends Exchange {
});
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.marketGetGetServerTime (params);
+ //
+ // {
+ // "status":200,
+ // "msg":"",
+ // "data":[],
+ // "time":1555490875,
+ // "microtime":"0.35994200 1555490875",
+ // "source":"api"
+ // }
+ //
+ return this.safeTimestamp (response, 'time');
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -25576,15 +34171,17 @@ module.exports = class bitz extends Exchange {
return this.parseTrades (response['data'], market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
- // { time: "1535973420000",
- // open: "0.03975084",
- // high: "0.03975084",
- // low: "0.03967700",
- // close: "0.03967700",
- // volume: "12.4733",
- // datetime: "2018-09-03 19:17:00" }
+ // {
+ // time: "1535973420000",
+ // open: "0.03975084",
+ // high: "0.03975084",
+ // low: "0.03967700",
+ // close: "0.03967700",
+ // volume: "12.4733",
+ // datetime: "2018-09-03 19:17:00"
+ // }
//
return [
this.safeInteger (ohlcv, 'time'),
@@ -25616,35 +34213,27 @@ module.exports = class bitz extends Exchange {
}
const response = await this.marketGetKline (this.extend (request, params));
//
- // { status: 200,
- // msg: "",
- // data: { bars: [ { time: "1535973420000",
- // open: "0.03975084",
- // high: "0.03975084",
- // low: "0.03967700",
- // close: "0.03967700",
- // volume: "12.4733",
- // datetime: "2018-09-03 19:17:00" },
- // { time: "1535955480000",
- // open: "0.04009900",
- // high: "0.04016745",
- // low: "0.04009900",
- // close: "0.04012074",
- // volume: "74.4803",
- // datetime: "2018-09-03 14:18:00" } ],
- // resolution: "1min",
- // symbol: "eth_btc",
- // from: "1535973420000",
- // to: "1535955480000",
- // size: 300 },
- // time: 1535973435,
- // microtime: "0.56462100 1535973435",
- // source: "api" }
+ // {
+ // status: 200,
+ // msg: "",
+ // data: {
+ // bars: [
+ // { time: "1535973420000", open: "0.03975084", high: "0.03975084", low: "0.03967700", close: "0.03967700", volume: "12.4733", datetime: "2018-09-03 19:17:00" },
+ // { time: "1535955480000", open: "0.04009900", high: "0.04016745", low: "0.04009900", close: "0.04012074", volume: "74.4803", datetime: "2018-09-03 14:18:00" },
+ // ],
+ // resolution: "1min",
+ // symbol: "eth_btc",
+ // from: "1535973420000",
+ // to: "1535955480000",
+ // size: 300
+ // },
+ // time: 1535973435,
+ // microtime: "0.56462100 1535973435",
+ // source: "api"
+ // }
//
- const bars = this.safeValue (response['data'], 'bars', undefined);
- if (bars === undefined) {
- return [];
- }
+ const data = this.safeValue (response, 'data', {});
+ const bars = this.safeValue (data, 'bars', []);
return this.parseOHLCVs (bars, market, timeframe, since, limit);
}
@@ -25722,8 +34311,10 @@ module.exports = class bitz extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -26040,6 +34631,16 @@ module.exports = class bitz extends Exchange {
// "memo":""
// }
//
+ // withdraw
+ //
+ // {
+ // "id":397574,
+ // "email":"***@email.com",
+ // "coin":"usdt",
+ // "network_fee":"",
+ // "eid":23112
+ // }
+ //
let timestamp = this.safeInteger (transaction, 'updated');
if (timestamp === 0) {
timestamp = undefined;
@@ -26048,6 +34649,14 @@ module.exports = class bitz extends Exchange {
const code = this.safeCurrencyCode (currencyId, currency);
const type = this.safeStringLower (transaction, 'type');
const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ let fee = undefined;
+ const feeCost = this.safeFloat (transaction, 'network_fee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'code': code,
+ };
+ }
return {
'id': this.safeString (transaction, 'id'),
'txid': this.safeString (transaction, 'txid'),
@@ -26060,7 +34669,7 @@ module.exports = class bitz extends Exchange {
'currency': code,
'status': status,
'updated': timestamp,
- 'fee': undefined,
+ 'fee': fee,
'info': transaction,
};
}
@@ -26114,6 +34723,40 @@ module.exports = class bitz extends Exchange {
return this.parseTransactionsByType (type, transactions, code, since, limit);
}
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'coin': currency['id'],
+ 'number': this.currencyToPrecision (code, amount),
+ 'address': address,
+ // 'type': 'erc20', // omni, trc20, optional
+ };
+ if (tag !== undefined) {
+ request['memo'] = tag;
+ }
+ const response = await this.tradePostCoinOut (this.extend (request, params));
+ //
+ // {
+ // "status":200,
+ // "msg":"",
+ // "data":{
+ // "id":397574,
+ // "email":"***@email.com",
+ // "coin":"usdt",
+ // "network_fee":"",
+ // "eid":23112
+ // },
+ // "time":1552641646,
+ // "microtime":"0.70304500 1552641646",
+ // "source":"api"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTransaction (data, currency);
+ }
+
nonce () {
const currentTimestamp = this.seconds ();
if (currentTimestamp > this.options['lastNonceTimestamp']) {
@@ -26174,7 +34817,7 @@ module.exports = class bitz extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],45:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],46:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -26194,14 +34837,17 @@ module.exports = class bl3p extends Exchange {
'comment': 'An exchange market by BitonicNL',
'has': {
'CORS': false,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/28501752-60c21b82-6feb-11e7-818b-055ee6d0e754.jpg',
'api': 'https://api.bl3p.eu',
- 'www': [
- 'https://bl3p.eu',
- 'https://bitonic.nl',
- ],
+ 'www': 'https://bl3p.eu', // 'https://bitonic.nl'
'doc': [
'https://github.com/BitonicNL/bl3p-api/tree/master/docs',
'https://bl3p.eu/api',
@@ -26402,14 +35048,14 @@ module.exports = class bl3p extends Exchange {
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Rest-Key': this.apiKey,
- 'Rest-Sign': this.decode (signature),
+ 'Rest-Sign': signature,
};
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
};
-},{"./base/Exchange":7}],46:[function(require,module,exports){
+},{"./base/Exchange":5}],47:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -26427,36 +35073,36 @@ module.exports = class bleutrade extends Exchange {
'rateLimit': 1000,
'certified': false,
'has': {
+ 'cancelOrder': true,
'CORS': true,
- 'cancelOrder': false, // todo
- 'createLimitOrder': false, // todo
- 'createMarketOrder': false, // todo
- 'createOrder': false, // todo
- 'editOrder': false, // todo
- 'withdraw': false, // todo
- 'fetchTrades': false,
- 'fetchTickers': true,
- 'fetchTicker': true,
- 'fetchOrders': false,
+ 'createLimitOrder': false,
+ 'createMarketOrder': false,
+ 'createOrder': true,
+ 'editOrder': false,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchOpenOrders': true,
- 'fetchWithdrawals': true,
- 'fetchOrderTrades': false,
- 'fetchLedger': true,
+ 'fetchCurrencies': true,
'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchOrderTrades': false,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': false,
},
'timeframes': {
- '15m': '15m',
- '20m': '20m',
- '30m': '30m',
'1h': '1h',
- '2h': '2h',
- '3h': '3h',
'4h': '4h',
- '6h': '6h',
'8h': '8h',
- '12h': '12h',
'1d': '1d',
+ '1w': '1w',
},
'hostname': 'bleutrade.com',
'urls': {
@@ -26465,7 +35111,7 @@ module.exports = class bleutrade extends Exchange {
'v3Private': 'https://{hostname}/api/v3/private',
'v3Public': 'https://{hostname}/api/v3/public',
},
- 'www': ['https://bleutrade.com'],
+ 'www': 'https://bleutrade.com',
'doc': [
'https://app.swaggerhub.com/apis-docs/bleu/white-label/3.0.0',
],
@@ -26517,6 +35163,7 @@ module.exports = class bleutrade extends Exchange {
'exact': {
'ERR_INSUFICIENT_BALANCE': InsufficientFunds,
'ERR_LOW_VOLUME': BadRequest,
+ 'Invalid form': BadRequest,
},
'broad': {
'Order is not open': InvalidOrder,
@@ -26533,7 +35180,6 @@ module.exports = class bleutrade extends Exchange {
},
'options': {
'parseOrderStatus': true,
- 'symbolSeparator': '_',
},
});
// undocumented api calls
@@ -26665,7 +35311,7 @@ module.exports = class bleutrade extends Exchange {
'market': market['id'],
};
const response = await this.v3PublicGetGetmarketsummary (this.extend (request, params));
- const ticker = response['result'][0];
+ const ticker = this.safeValue (response, 'result', {});
return this.parseTicker (ticker, market);
}
@@ -26702,18 +35348,8 @@ module.exports = class bleutrade extends Exchange {
// MarketCurrency: 'Litecoin',
// BaseCurrency: 'Tether' }
const timestamp = this.parse8601 (this.safeString (ticker, 'TimeStamp'));
- let symbol = undefined;
const marketId = this.safeString (ticker, 'MarketName');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- symbol = this.parseSymbol (marketId);
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const previous = this.safeFloat (ticker, 'PrevDay');
const last = this.safeFloat (ticker, 'Last');
let change = undefined;
@@ -26750,10 +35386,9 @@ module.exports = class bleutrade extends Exchange {
};
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
- const timestamp = this.parse8601 (ohlcv['TimeStamp'] + '+00:00');
+ parseOHLCV (ohlcv, market = undefined) {
return [
- timestamp,
+ this.parse8601 (ohlcv['TimeStamp'] + '+00:00'),
this.safeFloat (ohlcv, 'Open'),
this.safeFloat (ohlcv, 'High'),
this.safeFloat (ohlcv, 'Low'),
@@ -26771,7 +35406,8 @@ module.exports = class bleutrade extends Exchange {
'count': limit,
};
const response = await this.v3PublicGetGetcandles (this.extend (request, params));
- return this.parseOHLCVs (response['result'], market, timeframe, since, limit);
+ const result = this.safeValue (response, 'result', []);
+ return this.parseOHLCVs (result, market, timeframe, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
@@ -26823,13 +35459,6 @@ module.exports = class bleutrade extends Exchange {
return this.parseOrders (items, market, since, limit);
}
- parseSymbol (id) {
- let [ base, quote ] = id.split (this.options['symbolSeparator']);
- base = this.safeCurrencyCode (base);
- quote = this.safeCurrencyCode (quote);
- return base + '/' + quote;
- }
-
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.v3PrivatePostGetbalances (params);
@@ -27055,20 +35684,8 @@ module.exports = class bleutrade extends Exchange {
// Comments: { String: '', Valid: true }
const side = this.safeString (order, 'Type').toLowerCase ();
const status = this.parseOrderStatus (this.safeString (order, 'Status'));
- let symbol = undefined;
const marketId = this.safeString (order, 'Exchange');
- if (marketId === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- } else {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = this.parseSymbol (marketId);
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
let timestamp = undefined;
if ('Created' in order) {
timestamp = this.parse8601 (order['Created'] + '+00:00');
@@ -27102,8 +35719,10 @@ module.exports = class bleutrade extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -27230,27 +35849,28 @@ module.exports = class bleutrade extends Exchange {
// {"success":false,"message":"Erro: Order is not open.","result":""} <-- 'error' is spelt wrong
// {"success":false,"message":"Error: Very low volume.","result":"ERR_LOW_VOLUME"}
// {"success":false,"message":"Error: Insuficient Balance","result":"ERR_INSUFICIENT_BALANCE"}
+ // {"success":false,"message":"Invalid form","result":null}
//
- if (body[0] === '{') {
- const success = this.safeValue (response, 'success');
- if (success === undefined) {
- throw new ExchangeError (this.id + ': malformed response: ' + this.json (response));
- }
- if (!success) {
- const feedback = this.id + ' ' + body;
- const errorCode = this.safeString (response, 'result');
+ const success = this.safeValue (response, 'success');
+ if (success === undefined) {
+ throw new ExchangeError (this.id + ': malformed response: ' + this.json (response));
+ }
+ if (!success) {
+ const feedback = this.id + ' ' + body;
+ const errorCode = this.safeString (response, 'result');
+ if (errorCode !== undefined) {
this.throwBroadlyMatchedException (this.exceptions['broad'], errorCode, feedback);
this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
- const errorMessage = this.safeString (response, 'message');
- this.throwBroadlyMatchedException (this.exceptions['broad'], errorMessage, feedback);
- this.throwExactlyMatchedException (this.exceptions['exact'], errorMessage, feedback);
- throw new ExchangeError (feedback);
}
+ const errorMessage = this.safeString (response, 'message');
+ this.throwBroadlyMatchedException (this.exceptions['broad'], errorMessage, feedback);
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorMessage, feedback);
+ throw new ExchangeError (feedback);
}
}
};
-},{"./base/Exchange":7,"./base/errors":9}],47:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],48:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -27268,12 +35888,19 @@ module.exports = class braziliex extends Exchange {
'countries': [ 'BR' ],
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchCurrencies': true,
- 'fetchTickers': true,
- 'fetchOpenOrders': true,
- 'fetchMyTrades': true,
'fetchDepositAddress': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/34703593-c4498674-f504-11e7-8d14-ff8e44fb78c1.jpg',
@@ -27590,11 +36217,11 @@ module.exports = class braziliex extends Exchange {
const ids = Object.keys (response);
for (let i = 0; i < ids.length; i++) {
const marketId = ids[i];
- const market = this.markets_by_id[marketId];
+ const market = this.safeMarket (marketId);
const symbol = market['symbol'];
result[symbol] = this.parseTicker (response[marketId], market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -27676,16 +36303,8 @@ module.exports = class braziliex extends Exchange {
// "date":"2017-03-12 15:13:33"
// }
//
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'market');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'market');
+ const symbol = this.safeSymbol (marketId, market, '_');
let timestamp = this.safeInteger (order, 'timestamp');
if (timestamp === undefined) {
timestamp = this.parse8601 (this.safeString (order, 'date'));
@@ -27703,6 +36322,7 @@ module.exports = class braziliex extends Exchange {
const id = this.safeString (order, 'order_number');
const fee = this.safeValue (order, 'fee'); // propagated from createOrder
const status = (filledPercentage === 1.0) ? 'closed' : 'open';
+ const side = this.safeString (order, 'type');
return {
'id': id,
'clientOrderId': undefined,
@@ -27712,8 +36332,10 @@ module.exports = class braziliex extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
- 'side': order['type'],
+ 'timeInForce': undefined,
+ 'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -27737,30 +36359,49 @@ module.exports = class braziliex extends Exchange {
'amount': amount,
};
const response = await this[method] (this.extend (request, params));
+ //
+ // sell
+ //
+ // {
+ // "success":1,
+ // "message":" ##RESERVED FOR ORDER / SELL / XMR_BTC / AMOUNT: 0.01 XMR / PRICE: 0.017 BTC / TOTAL: 0.00017000 BTC / FEE: 0.00002500 XMR ",
+ // "order_number":"590b962ba5b98335965fa0a8"
+ // }
+ //
+ // buy
+ //
+ // {
+ // "success":1,
+ // "message":" ##RESERVED FOR ORDER / BUY / XMR_BTC / AMOUNT: 0.005 XMR / PRICE: 0.017 BTC / TOTAL: 0.00008500 BTC / FEE: 0.00000021 BTC ",
+ // "order_number":"590b962ba5b98335965fa0c0"
+ // }
+ //
const success = this.safeInteger (response, 'success');
if (success !== 1) {
throw new InvalidOrder (this.id + ' ' + this.json (response));
}
- let parts = response['message'].split (' / ');
+ const message = this.safeString (response, 'message');
+ let parts = message.split (' / ');
parts = parts.slice (1);
const feeParts = parts[5].split (' ');
+ const amountParts = parts[2].split (' ');
+ const priceParts = parts[3].split (' ');
+ const totalParts = parts[4].split (' ');
const order = this.parseOrder ({
'timestamp': this.milliseconds (),
'order_number': response['order_number'],
- 'type': parts[0].toLowerCase (),
+ 'type': this.safeStringLower (parts, 0),
'market': parts[0].toLowerCase (),
- 'amount': parts[2].split (' ')[1],
- 'price': parts[3].split (' ')[1],
- 'total': parts[4].split (' ')[1],
+ 'amount': this.safeString (amountParts, 1),
+ 'price': this.safeString (priceParts, 1),
+ 'total': this.safeString (totalParts, 1),
'fee': {
- 'cost': parseFloat (feeParts[1]),
- 'currency': feeParts[2],
+ 'cost': this.safeFloat (feeParts, 1),
+ 'currency': this.safeString (feeParts, 2),
},
'progress': '0.0',
'info': response,
}, market);
- const id = order['id'];
- this.orders[id] = order;
return order;
}
@@ -27795,7 +36436,8 @@ module.exports = class braziliex extends Exchange {
'market': market['id'],
};
const response = await this.privatePostOpenOrders (this.extend (request, params));
- return this.parseOrders (response['order_open'], market, since, limit);
+ const orders = this.safeValue (response, 'order_open', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -27805,7 +36447,8 @@ module.exports = class braziliex extends Exchange {
'market': market['id'],
};
const response = await this.privatePostTradeHistory (this.extend (request, params));
- return this.parseTrades (response['trade_history'], market, since, limit);
+ const trades = this.safeValue (response, 'trade_history', []);
+ return this.parseTrades (trades, market, since, limit);
}
async fetchDepositAddress (code, params = {}) {
@@ -27870,7 +36513,7 @@ module.exports = class braziliex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],48:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],49:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -27888,12 +36531,19 @@ module.exports = class btcalpha extends Exchange {
'countries': [ 'US' ],
'version': 'v1',
'has': {
- 'fetchTicker': false,
- 'fetchOHLCV': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': false,
+ 'fetchTrades': true,
},
'timeframes': {
'1m': '1',
@@ -28107,7 +36757,17 @@ module.exports = class btcalpha extends Exchange {
return this.parseTrades (trades, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "time":1591296000,
+ // "open":0.024746,
+ // "close":0.024728,
+ // "low":0.024728,
+ // "high":0.024753,
+ // "volume":16.624
+ // }
+ //
return [
this.safeTimestamp (ohlcv, 'time'),
this.safeFloat (ohlcv, 'open'),
@@ -28132,6 +36792,13 @@ module.exports = class btcalpha extends Exchange {
request['since'] = parseInt (since / 1000);
}
const response = await this.publicGetChartsPairTypeChart (this.extend (request, params));
+ //
+ // [
+ // {"time":1591296000,"open":0.024746,"close":0.024728,"low":0.024728,"high":0.024753,"volume":16.624},
+ // {"time":1591295700,"open":0.024718,"close":0.02475,"low":0.024711,"high":0.02475,"volume":31.645},
+ // {"time":1591295400,"open":0.024721,"close":0.024717,"low":0.024711,"high":0.02473,"volume":65.071}
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -28196,8 +36863,10 @@ module.exports = class btcalpha extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': undefined,
'amount': amount,
'filled': filled,
@@ -28348,7 +37017,7 @@ module.exports = class btcalpha extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],49:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],50:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -28367,17 +37036,23 @@ module.exports = class btcbox extends Exchange {
'rateLimit': 1000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchOrder': true,
- 'fetchOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
'fetchTickers': false,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/31275803-4df755a8-aaa1-11e7-9abb-11ec2fad9f2d.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87327317-98c55400-c53c-11ea-9a11-81f7d951cc74.jpg',
'api': 'https://www.btcbox.co.jp/api',
'www': 'https://www.btcbox.co.jp/',
- 'doc': 'https://www.btcbox.co.jp/help/asm',
+ 'doc': 'https://blog.btcbox.jp/en/archives/8762',
'fees': 'https://support.btcbox.co.jp/hc/en-us/articles/360001235694-Fees-introduction',
},
'api': {
@@ -28650,9 +37325,11 @@ module.exports = class btcbox extends Exchange {
'filled': filled,
'side': side,
'type': undefined,
+ 'timeInForce': undefined,
'status': status,
'symbol': symbol,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'trades': trades,
'fee': undefined,
@@ -28767,14 +37444,13 @@ module.exports = class btcbox extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],50:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],51:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, OrderNotFound, ArgumentsRequired, InvalidOrder, DDoSProtection } = require ('./base/errors');
-const { ROUND } = require ('./base/functions/number');
+const { ArgumentsRequired, ExchangeError, OrderNotFound, InvalidOrder, InsufficientFunds, DDoSProtection, BadRequest } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -28785,74 +37461,107 @@ module.exports = class btcmarkets extends Exchange {
'name': 'BTC Markets',
'countries': [ 'AU' ], // Australia
'rateLimit': 1000, // market data cached for 1 second (trades cached for 2 seconds)
+ 'version': 'v3',
'has': {
- 'CORS': false,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchClosedOrders': 'emulated',
- 'fetchOpenOrders': true,
- 'fetchMyTrades': true,
+ 'cancelOrder': true,
'cancelOrders': true,
+ 'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': 'emulated',
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
+ 'fetchWithdrawals': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/29142911-0e1acfc2-7d5c-11e7-98c4-07d9532b29d7.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/89731817-b3fb8480-da52-11ea-817f-783b08aaf32b.jpg',
'api': {
'public': 'https://api.btcmarkets.net',
'private': 'https://api.btcmarkets.net',
- 'web': 'https://btcmarkets.net/data',
},
'www': 'https://btcmarkets.net',
- 'doc': 'https://github.com/BTCMarkets/API',
+ 'doc': [
+ 'https://api.btcmarkets.net/doc/v3',
+ 'https://github.com/BTCMarkets/API',
+ ],
},
'api': {
'public': {
'get': [
- 'market/{id}/tick',
- 'market/{id}/orderbook',
- 'market/{id}/trades',
- 'v2/market/{id}/tickByTime/{timeframe}',
- 'v2/market/{id}/trades',
- 'v2/market/active',
+ 'markets',
+ 'markets/{marketId}/ticker',
+ 'markets/{marketId}/trades',
+ 'markets/{marketId}/orderbook',
+ 'markets/{marketId}/candles',
+ 'markets/tickers',
+ 'markets/orderbooks',
+ 'time',
],
},
'private': {
'get': [
- 'account/balance',
- 'account/{id}/tradingfee',
- 'fundtransfer/history',
- 'v2/order/open',
- 'v2/order/open/{id}',
- 'v2/order/history/{instrument}/{currency}/',
- 'v2/order/trade/history/{id}',
- 'v2/transaction/history/{currency}',
+ 'orders',
+ 'orders/{id}',
+ 'batchorders/{ids}',
+ 'trades',
+ 'trades/{id}',
+ 'withdrawals',
+ 'withdrawals/{id}',
+ 'deposits',
+ 'deposits/{id}',
+ 'transfers',
+ 'transfers/{id}',
+ 'addresses',
+ 'withdrawal-fees',
+ 'assets',
+ 'accounts/me/trading-fees',
+ 'accounts/me/withdrawal-limits',
+ 'accounts/me/balances',
+ 'accounts/me/transactions',
+ 'reports/{id}',
],
'post': [
- 'fundtransfer/withdrawCrypto',
- 'fundtransfer/withdrawEFT',
- 'order/create',
- 'order/cancel',
- 'order/history',
- 'order/open',
- 'order/trade/history',
- 'order/createBatch', // they promise it's coming soon...
- 'order/detail',
+ 'orders',
+ 'batchorders',
+ 'withdrawals',
+ 'reports',
],
- },
- 'web': {
- 'get': [
- 'market/BTCMarkets/{id}/tickByTime',
+ 'delete': [
+ 'orders',
+ 'orders/{id}',
+ 'batchorders/{ids}',
+ ],
+ 'put': [
+ 'orders/{id}',
],
},
},
'timeframes': {
- '1m': 'minute',
- '1h': 'hour',
- '1d': 'day',
+ '1m': '1m',
+ '1h': '1h',
+ '1d': '1d',
},
'exceptions': {
'3': InvalidOrder,
'6': DDoSProtection,
+ 'InsufficientFund': InsufficientFunds,
+ 'InvalidPrice': InvalidOrder,
+ 'InvalidAmount': InvalidOrder,
+ 'MissingArgument': InvalidOrder,
+ 'OrderAlreadyCancelled': InvalidOrder,
+ 'OrderNotFound': OrderNotFound,
+ 'OrderStatusIsFinal': InvalidOrder,
+ 'InvalidPaginationParameter': BadRequest,
},
'fees': {
'percentage': true,
@@ -28871,18 +37580,33 @@ module.exports = class btcmarkets extends Exchange {
});
}
- async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ async fetchTransactionsWithMethod (method, code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
if (limit !== undefined) {
request['limit'] = limit;
}
if (since !== undefined) {
- request['since'] = since;
+ request['after'] = since;
}
- const response = await this.privateGetFundtransferHistory (this.extend (request, params));
- const transactions = response['fundTransfers'];
- return this.parseTransactions (transactions, undefined, since, limit);
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ const response = await this[method] (this.extend (request, params));
+ return this.parseTransactions (response, currency, since, limit);
+ }
+
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsWithMethod ('privateGetTransfers', code, since, limit, params);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsWithMethod ('privateGetDeposits', code, since, limit, params);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsWithMethod ('privateGetWithdrawals', code, since, limit, params);
}
parseTransactionStatus (status) {
@@ -28893,83 +37617,101 @@ module.exports = class btcmarkets extends Exchange {
return this.safeString (statuses, status, status);
}
- parseTransaction (item, currency = undefined) {
+ parseTransactionType (type) {
+ const statuses = {
+ 'Withdraw': 'withdrawal',
+ 'Deposit': 'deposit',
+ };
+ return this.safeString (statuses, type, type);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
//
- // {
- // status: 'Complete',
- // fundTransferId: 1904311906,
- // description: 'ETH withdraw from [me@email.com] to Address: 0xF123aa44FadEa913a7da99cc2eE202Db684Ce0e3 amount: 8.28965701 fee: 0.00000000',
- // creationTime: 1529418358525,
- // currency: 'ETH',
- // amount: 828965701,
- // fee: 0,
- // transferType: 'WITHDRAW',
- // errorMessage: null,
- // lastUpdate: 1529418376754,
- // cryptoPaymentDetail: {
- // address: '0xF123aa44FadEa913a7da99cc2eE202Db684Ce0e3',
- // txId: '0x8fe483b6f9523559b9ebffb29624f98e86227d2660d4a1fd4785d45e51c662c2'
- // }
- // }
- //
- // {
- // status: 'Complete',
- // fundTransferId: 494077500,
- // description: 'BITCOIN Deposit, B 0.1000',
- // creationTime: 1501077601015,
- // currency: 'BTC',
- // amount: 10000000,
- // fee: 0,
- // transferType: 'DEPOSIT',
- // errorMessage: null,
- // lastUpdate: 1501077601133,
- // cryptoPaymentDetail: null
- // }
- //
- // {
- // "fee": 0,
- // "amount": 56,
+ // {
+ // "id": "6500230339",
+ // "assetName": "XRP",
+ // "amount": "500",
+ // "type": "Deposit",
+ // "creationTime": "2020-07-27T07:52:08.640000Z",
// "status": "Complete",
- // "currency": "BCHABC",
- // "lastUpdate": 1542339164044,
- // "description": "BitcoinCashABC Deposit, P 0.00000056",
- // "creationTime": 1542339164003,
- // "errorMessage": null,
- // "transferType": "DEPOSIT",
- // "fundTransferId": 2527326972,
- // "cryptoPaymentDetail": null
+ // "description": "RIPPLE Deposit, XRP 500",
+ // "fee": "0",
+ // "lastUpdate": "2020-07-27T07:52:08.665000Z",
+ // "paymentDetail": {
+ // "txId": "lsjflsjdfljsd",
+ // "address": "kjasfkjsdf?dt=873874545"
+ // }
+ // }
+ //
+ // {
+ // "id": "500985282",
+ // "assetName": "BTC",
+ // "amount": "0.42570126",
+ // "type": "Withdraw",
+ // "creationTime": "2017-07-29T12:49:03.931000Z",
+ // "status": "Complete",
+ // "description": "BTC withdraw from [nick-btcmarkets@snowmonkey.co.uk] to Address: 1B9DsnSYQ54VMqFHVJYdGoLMCYzFwrQzsj amount: 0.42570126 fee: 0.00000000",
+ // "fee": "0.0005",
+ // "lastUpdate": "2017-07-29T12:52:20.676000Z",
+ // "paymentDetail": {
+ // "txId": "fkjdsfjsfljsdfl",
+ // "address": "a;daddjas;djas"
+ // }
+ // }
+ //
+ // {
+ // "id": "505102262",
+ // "assetName": "XRP",
+ // "amount": "979.836",
+ // "type": "Deposit",
+ // "creationTime": "2017-07-31T08:50:01.053000Z",
+ // "status": "Complete",
+ // "description": "Ripple Deposit, X 979.8360",
+ // "fee": "0",
+ // "lastUpdate": "2017-07-31T08:50:01.290000Z"
// }
//
- const timestamp = this.safeInteger (item, 'creationTime');
- const lastUpdate = this.safeInteger (item, 'lastUpdate');
- const transferType = this.safeString (item, 'transferType');
- const cryptoPaymentDetail = this.safeValue (item, 'cryptoPaymentDetail', {});
- const address = this.safeString (cryptoPaymentDetail, 'address');
- const txid = this.safeString (cryptoPaymentDetail, 'txId');
- let type = undefined;
- if (transferType === 'DEPOSIT') {
- type = 'deposit';
- } else if (transferType === 'WITHDRAW') {
+ const timestamp = this.parse8601 (this.safeString (transaction, 'creationTime'));
+ const lastUpdate = this.parse8601 (this.safeString (transaction, 'lastUpdate'));
+ let type = this.parseTransactionType (this.safeStringLower (transaction, 'type'));
+ if (type === 'withdraw') {
type = 'withdrawal';
- } else {
- type = transferType;
}
- const fee = this.safeFloat (item, 'fee');
- const status = this.parseTransactionStatus (this.safeString (item, 'status'));
- const ccy = this.safeString (item, 'currency');
- const code = this.safeCurrencyCode (ccy);
- // todo: this logic is duplicated below
- let amount = this.safeFloat (item, 'amount');
- if (amount !== undefined) {
- amount = amount * 1e-8;
+ const cryptoPaymentDetail = this.safeValue (transaction, 'paymentDetail', {});
+ const txid = this.safeString (cryptoPaymentDetail, 'txId');
+ let address = this.safeString (cryptoPaymentDetail, 'address');
+ let tag = undefined;
+ if (address !== undefined) {
+ const addressParts = address.split ('?dt=');
+ const numParts = addressParts.length;
+ if (numParts > 1) {
+ address = addressParts[0];
+ tag = addressParts[1];
+ }
+ }
+ const addressTo = address;
+ const tagTo = tag;
+ const addressFrom = undefined;
+ const tagFrom = undefined;
+ const fee = this.safeFloat (transaction, 'fee');
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const currencyId = this.safeString (transaction, 'assetName');
+ const code = this.safeCurrencyCode (currencyId);
+ let amount = this.safeFloat (transaction, 'amount');
+ if (fee) {
+ amount -= fee;
}
return {
- 'id': this.safeString (item, 'fundTransferId'),
+ 'id': this.safeString (transaction, 'id'),
'txid': txid,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'address': address,
- 'tag': undefined,
+ 'addressTo': addressTo,
+ 'addressFrom': addressFrom,
+ 'tag': tag,
+ 'tagTo': tagTo,
+ 'tagFrom': tagFrom,
'type': type,
'amount': amount,
'currency': code,
@@ -28979,32 +37721,41 @@ module.exports = class btcmarkets extends Exchange {
'currency': code,
'cost': fee,
},
- 'info': item,
+ 'info': transaction,
};
}
async fetchMarkets (params = {}) {
- const response = await this.publicGetV2MarketActive (params);
+ const response = await this.publicGetMarkets (params);
+ //
+ // [
+ // {
+ // "marketId":"COMP-AUD",
+ // "baseAssetName":"COMP",
+ // "quoteAssetName":"AUD",
+ // "minOrderAmount":"0.00007",
+ // "maxOrderAmount":"1000000",
+ // "amountDecimals":"8",
+ // "priceDecimals":"2"
+ // }
+ // ]
+ //
const result = [];
- const markets = this.safeValue (response, 'markets');
- for (let i = 0; i < markets.length; i++) {
- const market = markets[i];
- const baseId = this.safeString (market, 'instrument');
- const quoteId = this.safeString (market, 'currency');
- const id = baseId + '/' + quoteId;
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ const baseId = this.safeString (market, 'baseAssetName');
+ const quoteId = this.safeString (market, 'quoteAssetName');
+ const id = this.safeString (market, 'marketId');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
const fees = this.safeValue (this.safeValue (this.options, 'fees', {}), quote, this.fees);
- let pricePrecision = 2;
- let amountPrecision = 4;
- const minAmount = 0.001; // where does it come from?
+ const pricePrecision = this.safeFloat (market, 'priceDecimals');
+ const amountPrecision = this.safeFloat (market, 'amountDecimals');
+ const minAmount = this.safeFloat (market, 'minOrderAmount');
+ const maxAmount = this.safeFloat (market, 'maxOrderAmount');
let minPrice = undefined;
if (quote === 'AUD') {
- if ((base === 'XRP') || (base === 'OMG')) {
- pricePrecision = 4;
- }
- amountPrecision = -Math.log10 (minAmount);
minPrice = Math.pow (10, -pricePrecision);
}
const precision = {
@@ -29014,7 +37765,7 @@ module.exports = class btcmarkets extends Exchange {
const limits = {
'amount': {
'min': minAmount,
- 'max': undefined,
+ 'max': maxAmount,
},
'price': {
'min': minPrice,
@@ -29043,23 +37794,26 @@ module.exports = class btcmarkets extends Exchange {
return result;
}
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // {
+ // "timestamp": "2019-09-01T18:34:27.045000Z"
+ // }
+ //
+ return this.parse8601 (this.safeString (response, 'timestamp'));
+ }
+
async fetchBalance (params = {}) {
await this.loadMarkets ();
- const balances = await this.privateGetAccountBalance (params);
- const result = { 'info': balances };
- for (let i = 0; i < balances.length; i++) {
- const balance = balances[i];
- const currencyId = this.safeString (balance, 'currency');
+ const response = await this.privateGetAccountsMeBalances (params);
+ const result = { 'info': response };
+ for (let i = 0; i < response.length; i++) {
+ const balance = response[i];
+ const currencyId = this.safeString (balance, 'assetName');
const code = this.safeCurrencyCode (currencyId);
- const multiplier = 100000000;
- let total = this.safeFloat (balance, 'balance');
- if (total !== undefined) {
- total /= multiplier;
- }
- let used = this.safeFloat (balance, 'pendingFunds');
- if (used !== undefined) {
- used /= multiplier;
- }
+ const total = this.safeFloat (balance, 'balance');
+ const used = this.safeFloat (balance, 'locked');
const account = this.account ();
account['used'] = used;
account['total'] = total;
@@ -29068,114 +37822,175 @@ module.exports = class btcmarkets extends Exchange {
return this.parseBalance (result);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
- // {
- // "timestamp":1572307200000,
- // "open":1962218,
- // "high":1974850,
- // "low":1962208,
- // "close":1974850,
- // "volume":305211315,
- // }
+ // [
+ // "2020-09-12T18:30:00.000000Z",
+ // "14409.45", // open
+ // "14409.45", // high
+ // "14403.91", // low
+ // "14403.91", // close
+ // "0.01571701" // volume
+ // ]
//
- const multiplier = 100000000; // for price and volume
- const keys = [ 'open', 'high', 'low', 'close', 'volume' ];
- const result = [
- this.safeInteger (ohlcv, 'timestamp'),
+ return [
+ this.parse8601 (this.safeString (ohlcv, 0)),
+ this.safeFloat (ohlcv, 1), // open
+ this.safeFloat (ohlcv, 2), // high
+ this.safeFloat (ohlcv, 3), // low
+ this.safeFloat (ohlcv, 4), // close
+ this.safeFloat (ohlcv, 5), // volume
];
- for (let i = 0; i < keys.length; i++) {
- const key = keys[i];
- let value = this.safeFloat (ohlcv, key);
- if (value !== undefined) {
- value = value / multiplier;
- }
- result.push (value);
- }
- return result;
}
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
- await this.load_markets ();
+ await this.loadMarkets ();
const market = this.market (symbol);
const request = {
- 'id': market['id'],
- 'timeframe': this.timeframes[timeframe],
- // set to true to see candles more recent than the timestamp in the
- // since parameter, if a since parameter is used, default is false
- 'indexForward': true,
- // set to true to see the earliest candles first in the list of
- // returned candles in chronological order, default is false
- 'sortForward': true,
+ 'marketId': market['id'],
+ 'timeWindow': this.timeframes[timeframe],
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()),
+ // 'before': 1234567890123,
+ // 'after': 1234567890123,
+ // 'limit': limit, // default 10, max 200
};
if (since !== undefined) {
- request['since'] = since;
+ request['from'] = this.iso8601 (since);
}
if (limit !== undefined) {
- request['limit'] = limit; // default is 3000
+ request['limit'] = limit; // default is 10, max 200
}
- const response = await this.publicGetV2MarketIdTickByTimeTimeframe (this.extend (request, params));
+ const response = await this.publicGetMarketsMarketIdCandles (this.extend (request, params));
//
- // {
- // "success":true,
- // "paging":{
- // "newer":"/v2/market/ETH/BTC/tickByTime/day?indexForward=true&since=1572307200000",
- // "older":"/v2/market/ETH/BTC/tickByTime/day?since=1457827200000"
- // },
- // "ticks":[
- // {"timestamp":1572307200000,"open":1962218,"high":1974850,"low":1962208,"close":1974850,"volume":305211315},
- // {"timestamp":1572220800000,"open":1924700,"high":1951276,"low":1909328,"close":1951276,"volume":1086067595},
- // {"timestamp":1572134400000,"open":1962155,"high":1962734,"low":1900905,"close":1930243,"volume":790141098},
- // ],
- // }
+ // [
+ // ["2020-09-12T18:30:00.000000Z","14409.45","14409.45","14403.91","14403.91","0.01571701"],
+ // ["2020-09-12T18:21:00.000000Z","14409.45","14409.45","14409.45","14409.45","0.0035"],
+ // ["2020-09-12T18:03:00.000000Z","14361.37","14361.37","14361.37","14361.37","0.00345221"],
+ // ]
//
- const ticks = this.safeValue (response, 'ticks', []);
- return this.parseOHLCVs (ticks, market, timeframe, since, limit);
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
- 'id': market['id'],
+ 'marketId': market['id'],
};
- const response = await this.publicGetMarketIdOrderbook (this.extend (request, params));
- const timestamp = this.safeTimestamp (response, 'timestamp');
- return this.parseOrderBook (response, timestamp);
+ const response = await this.publicGetMarketsMarketIdOrderbook (this.extend (request, params));
+ //
+ // {
+ // "marketId":"BTC-AUD",
+ // "snapshotId":1599936148941000,
+ // "asks":[
+ // ["14459.45","0.00456475"],
+ // ["14463.56","2"],
+ // ["14470.91","0.98"],
+ // ],
+ // "bids":[
+ // ["14421.01","0.52"],
+ // ["14421","0.75"],
+ // ["14418","0.3521"],
+ // ]
+ // }
+ //
+ const timestamp = this.safeIntegerProduct (response, 'snapshotId', 0.001);
+ const orderbook = this.parseOrderBook (response, timestamp);
+ orderbook['nonce'] = this.safeInteger (response, 'snapshotId');
+ return orderbook;
}
parseTicker (ticker, market = undefined) {
- const timestamp = this.safeTimestamp (ticker, 'timestamp');
+ //
+ // fetchTicker
+ //
+ // {
+ // "marketId":"BAT-AUD",
+ // "bestBid":"0.3751",
+ // "bestAsk":"0.377",
+ // "lastPrice":"0.3769",
+ // "volume24h":"56192.97613335",
+ // "volumeQte24h":"21179.13270465",
+ // "price24h":"0.0119",
+ // "pricePct24h":"3.26",
+ // "low24h":"0.3611",
+ // "high24h":"0.3799",
+ // "timestamp":"2020-08-09T18:28:23.280000Z"
+ // }
+ //
let symbol = undefined;
- if (market !== undefined) {
+ const marketId = this.safeString (ticker, 'marketId');
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const [ baseId, quoteId ] = marketId.split ('-');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
+ const timestamp = this.parse8601 (this.safeString (ticker, 'timestamp'));
const last = this.safeFloat (ticker, 'lastPrice');
+ const baseVolume = this.safeFloat (ticker, 'volume24h');
+ const quoteVolume = this.safeFloat (ticker, 'volumeQte24h');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ const change = this.safeFloat (ticker, 'price24h');
+ const percentage = this.safeFloat (ticker, 'pricePct24h');
return {
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'high': undefined,
- 'low': undefined,
+ 'high': this.safeFloat (ticker, 'high24h'),
+ 'low': this.safeFloat (ticker, 'low'),
'bid': this.safeFloat (ticker, 'bestBid'),
'bidVolume': undefined,
'ask': this.safeFloat (ticker, 'bestAsk'),
'askVolume': undefined,
- 'vwap': undefined,
+ 'vwap': vwap,
'open': undefined,
'close': last,
'last': last,
'previousClose': undefined,
- 'change': undefined,
- 'percentage': undefined,
+ 'change': change,
+ 'percentage': percentage,
'average': undefined,
- 'baseVolume': this.safeFloat (ticker, 'volume24h'),
- 'quoteVolume': undefined,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
'info': ticker,
};
}
async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'marketId': market['id'],
+ };
+ const response = await this.publicGetMarketsMarketIdTicker (this.extend (request, params));
+ //
+ // {
+ // "marketId":"BAT-AUD",
+ // "bestBid":"0.3751",
+ // "bestAsk":"0.377",
+ // "lastPrice":"0.3769",
+ // "volume24h":"56192.97613335",
+ // "volumeQte24h":"21179.13270465",
+ // "price24h":"0.0119",
+ // "pricePct24h":"3.26",
+ // "low24h":"0.3611",
+ // "high24h":"0.3799",
+ // "timestamp":"2020-08-09T18:28:23.280000Z"
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ async fetchTicker2 (symbol, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
@@ -29186,12 +38001,65 @@ module.exports = class btcmarkets extends Exchange {
}
parseTrade (trade, market = undefined) {
- const timestamp = this.safeTimestamp (trade, 'date');
+ //
+ // public fetchTrades
+ //
+ // {
+ // "id":"6191646611",
+ // "price":"539.98",
+ // "amount":"0.5",
+ // "timestamp":"2020-08-09T15:21:05.016000Z",
+ // "side":"Ask"
+ // }
+ //
+ // private fetchMyTrades
+ //
+ // {
+ // "id": "36014819",
+ // "marketId": "XRP-AUD",
+ // "timestamp": "2019-06-25T16:01:02.977000Z",
+ // "price": "0.67",
+ // "amount": "1.50533262",
+ // "side": "Ask",
+ // "fee": "0.00857285",
+ // "orderId": "3648306",
+ // "liquidityType": "Taker",
+ // "clientOrderId": "48"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (trade, 'timestamp'));
+ const marketId = this.safeString (trade, 'marketId');
let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
+ let base = undefined;
+ let quote = undefined;
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const [ baseId, quoteId ] = marketId.split ('-');
+ base = this.safeCurrencyCode (baseId);
+ quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
}
- const id = this.safeString (trade, 'tid');
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ base = market['base'];
+ quote = market['quote'];
+ }
+ let feeCurrencyCode = undefined;
+ if (quote === 'AUD') {
+ feeCurrencyCode = quote;
+ } else {
+ feeCurrencyCode = base;
+ }
+ let side = this.safeString (trade, 'side');
+ if (side === 'Bid') {
+ side = 'buy';
+ } else if (side === 'Ask') {
+ side = 'sell';
+ }
+ const id = this.safeString (trade, 'id');
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'amount');
let cost = undefined;
@@ -29200,20 +38068,30 @@ module.exports = class btcmarkets extends Exchange {
cost = amount * price;
}
}
+ const orderId = this.safeString (trade, 'orderId');
+ let fee = undefined;
+ const feeCost = this.safeFloat (trade, 'fee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ const takerOrMaker = this.safeStringLower (trade, 'liquidityType');
return {
'info': trade,
'id': id,
- 'order': undefined,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
+ 'order': orderId,
'symbol': symbol,
'type': undefined,
- 'side': undefined,
- 'takerOrMaker': undefined,
+ 'side': side,
'price': price,
'amount': amount,
'cost': cost,
- 'fee': undefined,
+ 'takerOrMaker': takerOrMaker,
+ 'fee': fee,
};
}
@@ -29222,33 +38100,101 @@ module.exports = class btcmarkets extends Exchange {
const market = this.market (symbol);
const request = {
// 'since': 59868345231,
- 'id': market['id'],
+ 'marketId': market['id'],
};
- const response = await this.publicGetMarketIdTrades (this.extend (request, params));
+ const response = await this.publicGetMarketsMarketIdTrades (this.extend (request, params));
+ //
+ // [
+ // {"id":"6191646611","price":"539.98","amount":"0.5","timestamp":"2020-08-09T15:21:05.016000Z","side":"Ask"},
+ // {"id":"6191646610","price":"539.99","amount":"0.5","timestamp":"2020-08-09T15:21:05.015000Z","side":"Ask"},
+ // {"id":"6191646590","price":"540","amount":"0.00233785","timestamp":"2020-08-09T15:21:04.171000Z","side":"Bid"},
+ // ]
+ //
return this.parseTrades (response, market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
- const multiplier = 100000000; // for price and volume
- const orderSide = (side === 'buy') ? 'Bid' : 'Ask';
- const request = this.ordered ({
- 'currency': market['quote'],
- });
- request['currency'] = market['quote'];
- request['instrument'] = market['base'];
- request['price'] = parseInt (this.decimalToPrecision (price * multiplier, ROUND, 0));
- request['volume'] = parseInt (this.decimalToPrecision (amount * multiplier, ROUND, 0));
- request['orderSide'] = orderSide;
- request['ordertype'] = this.capitalize (type);
- request['clientRequestId'] = this.nonce ().toString ();
- const response = await this.privatePostOrderCreate (this.extend (request, params));
- const id = this.safeString (response, 'id');
- return {
- 'info': response,
- 'id': id,
+ const request = {
+ 'marketId': market['id'],
+ // 'price': this.priceToPrecision (symbol, price),
+ 'amount': this.amountToPrecision (symbol, amount),
+ // 'type': 'Limit', // "Limit", "Market", "Stop Limit", "Stop", "Take Profit"
+ 'side': (side === 'buy') ? 'Bid' : 'Ask',
+ // 'triggerPrice': this.priceToPrecision (symbol, triggerPrice), // required for Stop, Stop Limit, Take Profit orders
+ // 'targetAmount': this.amountToPrecision (symbol, targetAmount), // target amount when a desired target outcome is required for order execution
+ // 'timeInForce': 'GTC', // GTC, FOK, IOC
+ // 'postOnly': false, // boolean if this is a post-only order
+ // 'selfTrade': 'A', // A = allow, P = prevent
+ // 'clientOrderId': this.uuid (),
};
+ const lowercaseType = type.toLowerCase ();
+ const orderTypes = this.safeValue (this.options, 'orderTypes', {
+ 'limit': 'Limit',
+ 'market': 'Market',
+ 'stop': 'Stop',
+ 'stop limit': 'Stop Limit',
+ 'take profit': 'Take Profit',
+ });
+ request['type'] = this.safeString (orderTypes, lowercaseType, type);
+ let priceIsRequired = false;
+ let triggerPriceIsRequired = false;
+ if (lowercaseType === 'limit') {
+ priceIsRequired = true;
+ // } else if (lowercaseType === 'market') {
+ // ...
+ // }
+ } else if (lowercaseType === 'stop limit') {
+ triggerPriceIsRequired = true;
+ priceIsRequired = true;
+ } else if (lowercaseType === 'take profit') {
+ triggerPriceIsRequired = true;
+ } else if (lowercaseType === 'stop') {
+ triggerPriceIsRequired = true;
+ }
+ if (priceIsRequired) {
+ if (price === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder() requires a price argument for a ' + type + 'order');
+ } else {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ }
+ if (triggerPriceIsRequired) {
+ const triggerPrice = this.safeFloat (params, 'triggerPrice');
+ params = this.omit (params, 'triggerPrice');
+ if (triggerPrice === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder() requires a triggerPrice parameter for a ' + type + 'order');
+ } else {
+ request['triggerPrice'] = this.priceToPrecision (symbol, triggerPrice);
+ }
+ }
+ const clientOrderId = this.safeString (params, 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['clientOrderId'] = clientOrderId;
+ }
+ params = this.omit (params, 'clientOrderId');
+ const response = await this.privatePostOrders (this.extend (request, params));
+ //
+ // {
+ // "orderId": "7524",
+ // "marketId": "BTC-AUD",
+ // "side": "Bid",
+ // "type": "Limit",
+ // "creationTime": "2019-08-30T11:08:21.956000Z",
+ // "price": "100.12",
+ // "amount": "1.034",
+ // "openAmount": "1.034",
+ // "status": "Accepted",
+ // "clientOrderId": "1234-5678",
+ // "timeInForce": "IOC",
+ // "postOnly": false,
+ // "selfTrade": "P",
+ // "triggerAmount": "105",
+ // "targetAmount": "1000"
+ // }
+ //
+ return this.parseOrder (response, market);
}
async cancelOrders (ids, symbol = undefined, params = {}) {
@@ -29257,14 +38203,17 @@ module.exports = class btcmarkets extends Exchange {
ids[i] = parseInt (ids[i]);
}
const request = {
- 'orderIds': ids,
+ 'ids': ids,
};
- return await this.privatePostOrderCancel (this.extend (request, params));
+ return await this.privateDeleteBatchordersIds (this.extend (request, params));
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- return await this.cancelOrders ([ id ]);
+ const request = {
+ 'id': id,
+ };
+ return await this.privateDeleteOrdersId (this.extend (request, params));
}
calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) {
@@ -29287,172 +38236,138 @@ module.exports = class btcmarkets extends Exchange {
};
}
- parseMyTrade (trade, market) {
- const multiplier = 100000000;
- const timestamp = this.safeInteger (trade, 'creationTime');
- let side = this.safeFloat (trade, 'side');
- side = (side === 'Bid') ? 'buy' : 'sell';
- // BTCMarkets always charge in AUD for AUD-related transactions.
- let feeCurrencyCode = undefined;
- let symbol = undefined;
- if (market !== undefined) {
- feeCurrencyCode = (market['quote'] === 'AUD') ? market['quote'] : market['base'];
- symbol = market['symbol'];
- }
- const id = this.safeString (trade, 'id');
- let price = this.safeFloat (trade, 'price');
- if (price !== undefined) {
- price /= multiplier;
- }
- let amount = this.safeFloat (trade, 'volume');
- if (amount !== undefined) {
- amount /= multiplier;
- }
- let feeCost = this.safeFloat (trade, 'fee');
- if (feeCost !== undefined) {
- feeCost /= multiplier;
- }
- let cost = undefined;
- if (price !== undefined) {
- if (amount !== undefined) {
- cost = price * amount;
- }
- }
- const orderId = this.safeString (trade, 'orderId');
- return {
- 'info': trade,
- 'id': id,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'order': orderId,
- 'symbol': symbol,
- 'type': undefined,
- 'side': side,
- 'price': price,
- 'amount': amount,
- 'cost': cost,
- 'fee': {
- 'currency': feeCurrencyCode,
- 'cost': feeCost,
- },
- 'takerOrMaker': undefined,
+ parseOrderStatus (status) {
+ const statuses = {
+ 'Accepted': 'open',
+ 'Placed': 'open',
+ 'Partially Matched': 'open',
+ 'Fully Matched': 'closed',
+ 'Cancelled': 'canceled',
+ 'Partially Cancelled': 'canceled',
+ 'Failed': 'rejected',
};
- }
-
- parseMyTrades (trades, market = undefined, since = undefined, limit = undefined) {
- const result = [];
- for (let i = 0; i < trades.length; i++) {
- const trade = this.parseMyTrade (trades[i], market);
- result.push (trade);
- }
- return result;
+ return this.safeString (statuses, status, status);
}
parseOrder (order, market = undefined) {
- const multiplier = 100000000;
- const side = (order['orderSide'] === 'Bid') ? 'buy' : 'sell';
- const type = (order['ordertype'] === 'Limit') ? 'limit' : 'market';
- const timestamp = this.safeInteger (order, 'creationTime');
- if (market === undefined) {
- market = this.market (order['instrument'] + '/' + order['currency']);
- }
- let status = 'open';
- if (order['status'] === 'Failed' || order['status'] === 'Cancelled' || order['status'] === 'Partially Cancelled' || order['status'] === 'Error') {
- status = 'canceled';
- } else if (order['status'] === 'Fully Matched' || order['status'] === 'Partially Matched') {
- status = 'closed';
- }
- const price = this.safeFloat (order, 'price') / multiplier;
- const amount = this.safeFloat (order, 'volume') / multiplier;
- const remaining = this.safeFloat (order, 'openVolume', 0.0) / multiplier;
- const filled = amount - remaining;
- const trades = this.parseMyTrades (order['trades'], market);
- const numTrades = trades.length;
- let cost = filled * price;
- let average = undefined;
- let lastTradeTimestamp = undefined;
- if (numTrades > 0) {
- cost = 0;
- for (let i = 0; i < numTrades; i++) {
- const trade = trades[i];
- cost = this.sum (cost, trade['cost']);
+ //
+ // createOrder
+ //
+ // {
+ // "orderId": "7524",
+ // "marketId": "BTC-AUD",
+ // "side": "Bid",
+ // "type": "Limit",
+ // "creationTime": "2019-08-30T11:08:21.956000Z",
+ // "price": "100.12",
+ // "amount": "1.034",
+ // "openAmount": "1.034",
+ // "status": "Accepted",
+ // "clientOrderId": "1234-5678",
+ // "timeInForce": "IOC",
+ // "postOnly": false,
+ // "selfTrade": "P",
+ // "triggerAmount": "105",
+ // "targetAmount": "1000"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (order, 'creationTime'));
+ const marketId = this.safeString (order, 'marketId');
+ let symbol = undefined;
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const [ baseId, quoteId ] = marketId.split ('-');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
}
- if (filled > 0) {
- average = cost / filled;
- }
- lastTradeTimestamp = trades[numTrades - 1]['timestamp'];
}
- const id = this.safeString (order, 'id');
- const clientOrderId = this.safeString (order, 'clientRequestId');
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ let side = this.safeString (order, 'side');
+ if (side === 'Bid') {
+ side = 'buy';
+ } else if (side === 'Ask') {
+ side = 'sell';
+ }
+ const type = this.safeStringLower (order, 'type');
+ const price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'amount');
+ const remaining = this.safeFloat (order, 'openAmount');
+ let filled = undefined;
+ if ((amount !== undefined) && (remaining !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ let cost = undefined;
+ if (price !== undefined) {
+ if (filled !== undefined) {
+ cost = price * filled;
+ }
+ }
+ const id = this.safeString (order, 'orderId');
+ const clientOrderId = this.safeString (order, 'clientOrderId');
+ const timeInForce = this.safeString (order, 'timeInForce');
+ const stopPrice = this.safeFloat (order, 'triggerPrice');
return {
'info': order,
'id': id,
'clientOrderId': clientOrderId,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'lastTradeTimestamp': lastTradeTimestamp,
- 'symbol': market['symbol'],
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'cost': cost,
'amount': amount,
'filled': filled,
'remaining': remaining,
- 'average': average,
+ 'average': undefined,
'status': status,
- 'trades': trades,
+ 'trades': undefined,
'fee': undefined,
};
}
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- const ids = [ parseInt (id) ];
const request = {
- 'orderIds': ids,
+ 'id': id,
};
- const response = await this.privatePostOrderDetail (this.extend (request, params));
- const numOrders = response['orders'].length;
- if (numOrders < 1) {
- throw new OrderNotFound (this.id + ' No matching order found: ' + id);
- }
- const order = response['orders'][0];
- return this.parseOrder (order);
- }
-
- createPaginatedRequest (market, since = undefined, limit = undefined) {
- limit = (limit === undefined) ? 100 : limit;
- since = (since === undefined) ? 0 : since;
- const request = this.ordered ({
- 'currency': market['quoteId'],
- 'instrument': market['baseId'],
- 'limit': limit,
- 'since': since,
- });
- return request;
+ const response = await this.privateGetOrdersId (this.extend (request, params));
+ return this.parseOrder (response);
}
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- if (symbol === undefined) {
- throw new ArgumentsRequired (this.id + ': fetchOrders requires a `symbol` argument.');
- }
await this.loadMarkets ();
- const market = this.market (symbol);
- const request = this.createPaginatedRequest (market, since, limit);
- const response = await this.privatePostOrderHistory (this.extend (request, params));
- return this.parseOrders (response['orders'], market);
+ const request = {
+ 'status': 'all',
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['marketId'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['after'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetOrders (this.extend (request, params));
+ return this.parseOrders (response, market, since, limit);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- if (symbol === undefined) {
- throw new ArgumentsRequired (this.id + ': fetchOpenOrders requires a `symbol` argument.');
- }
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = this.createPaginatedRequest (market, since, limit);
- const response = await this.privatePostOrderOpen (this.extend (request, params));
- return this.parseOrders (response['orders'], market);
+ const request = { 'status': 'open' };
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
}
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -29461,14 +38376,67 @@ module.exports = class btcmarkets extends Exchange {
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- if (symbol === undefined) {
- throw new ArgumentsRequired (this.id + ': fetchMyTrades requires a `symbol` argument.');
- }
await this.loadMarkets ();
- const market = this.market (symbol);
- const request = this.createPaginatedRequest (market, since, limit);
- const response = await this.privatePostOrderTradeHistory (this.extend (request, params));
- return this.parseMyTrades (response['trades'], market);
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['marketId'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['after'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id": "36014819",
+ // "marketId": "XRP-AUD",
+ // "timestamp": "2019-06-25T16:01:02.977000Z",
+ // "price": "0.67",
+ // "amount": "1.50533262",
+ // "side": "Ask",
+ // "fee": "0.00857285",
+ // "orderId": "3648306",
+ // "liquidityType": "Taker",
+ // "clientOrderId": "48"
+ // },
+ // {
+ // "id": "3568960",
+ // "marketId": "GNT-AUD",
+ // "timestamp": "2019-06-20T08:44:04.488000Z",
+ // "price": "0.1362",
+ // "amount": "0.85",
+ // "side": "Bid",
+ // "fee": "0.00098404",
+ // "orderId": "3543015",
+ // "liquidityType": "Maker"
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ lookupSymbolFromMarketId (marketId) {
+ let market = undefined;
+ let symbol = undefined;
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const [ baseId, quoteId ] = marketId.split ('-');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ return symbol;
}
nonce () {
@@ -29476,39 +38444,36 @@ module.exports = class btcmarkets extends Exchange {
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- const uri = '/' + this.implodeParams (path, params);
- let url = this.urls['api'][api] + uri;
+ let request = '/' + this.version + '/' + this.implodeParams (path, params);
+ const query = this.keysort (this.omit (params, this.extractParams (path)));
if (api === 'private') {
this.checkRequiredCredentials ();
const nonce = this.nonce ().toString ();
- let auth = undefined;
- headers = {
- 'apikey': this.apiKey,
- 'timestamp': nonce,
- };
- if (method === 'POST') {
- headers['Content-Type'] = 'application/json';
- auth = uri + "\n" + nonce + "\n"; // eslint-disable-line quotes
- body = this.json (params);
- auth += body;
- } else {
- const query = this.keysort (this.omit (params, this.extractParams (path)));
- let queryString = '';
+ const secret = this.base64ToBinary (this.encode (this.secret));
+ let auth = method + request + nonce;
+ if ((method === 'GET') || (method === 'DELETE')) {
if (Object.keys (query).length) {
- queryString = this.urlencode (query);
- url += '?' + queryString;
- queryString += "\n"; // eslint-disable-line quotes
+ request += '?' + this.urlencode (query);
}
- auth = uri + "\n" + queryString + nonce + "\n"; // eslint-disable-line quotes
+ } else {
+ body = this.json (query);
+ auth += body;
}
- const secret = this.base64ToBinary (this.secret);
const signature = this.hmac (this.encode (auth), secret, 'sha512', 'base64');
- headers['signature'] = this.decode (signature);
- } else {
- if (Object.keys (params).length) {
- url += '?' + this.urlencode (params);
+ headers = {
+ 'Accept': 'application/json',
+ 'Accept-Charset': 'UTF-8',
+ 'Content-Type': 'application/json',
+ 'BM-AUTH-APIKEY': this.apiKey,
+ 'BM-AUTH-TIMESTAMP': nonce,
+ 'BM-AUTH-SIGNATURE': signature,
+ };
+ } else if (api === 'public') {
+ if (Object.keys (query).length) {
+ request += '?' + this.urlencode (query);
}
}
+ const url = this.urls['api'][api] + request;
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
@@ -29524,83 +38489,19 @@ module.exports = class btcmarkets extends Exchange {
throw new ExchangeError (feedback);
}
}
+ // v3 api errors
+ if (code >= 400) {
+ const errorCode = this.safeString (response, 'code');
+ const message = this.safeString (response, 'message');
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions, errorCode, feedback);
+ this.throwExactlyMatchedException (this.exceptions, message, feedback);
+ throw new ExchangeError (feedback);
+ }
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],51:[function(require,module,exports){
-'use strict';
-
-// ---------------------------------------------------------------------------
-
-const coinegg = require ('./coinegg.js');
-const { ExchangeError } = require ('./base/errors');
-
-// ---------------------------------------------------------------------------
-
-module.exports = class btctradeim extends coinegg {
- describe () {
- const result = this.deepExtend (super.describe (), {
- 'id': 'btctradeim',
- 'name': 'BtcTrade.im',
- 'countries': [ 'HK' ],
- 'urls': {
- 'referral': 'https://m.baobi.com/invite?inv=1765b2',
- 'logo': 'https://user-images.githubusercontent.com/1294454/36770531-c2142444-1c5b-11e8-91e2-a4d90dc85fe8.jpg',
- 'api': {
- 'web': 'https://api.btctrade.im/coin',
- 'rest': 'https://api.btctrade.im/api/v1',
- },
- 'www': 'https://www.btctrade.im',
- 'doc': 'https://www.btctrade.im/help.api.html',
- 'fees': 'https://www.btctrade.im/spend.price.html',
- },
- 'status': {
- 'status': 'error',
- 'updated': undefined,
- 'eta': undefined,
- 'url': undefined,
- },
- 'fees': {
- 'trading': {
- 'maker': 0.2 / 100,
- 'taker': 0.2 / 100,
- },
- 'funding': {
- 'withdraw': {
- 'BTC': 0.001,
- },
- },
- },
- // see the fix below
- // 'options': {
- // 'quoteIds': [ 'btc', 'eth', 'usc' ],
- // },
- });
- // a fix for PHP array_merge not overwriting "lists" (integer-indexed arrays)
- // https://github.com/ccxt/ccxt/issues/3343
- result['options']['quoteIds'] = [ 'btc', 'eth', 'usc' ];
- return result;
- }
-
- async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- const response = await this.fetch2 (path, api, method, params, headers, body);
- if (api === 'web') {
- return response;
- }
- const data = this.safeValue (response, 'data');
- if (data) {
- const code = this.safeString (response, 'code');
- if (code !== '0') {
- const message = this.safeString (response, 'msg', 'Error');
- throw new ExchangeError (message);
- }
- return data;
- }
- return response;
- }
-};
-
-},{"./base/errors":9,"./coinegg.js":64}],52:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],52:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -29618,9 +38519,15 @@ module.exports = class btctradeua extends Exchange {
'countries': [ 'UA' ], // Ukraine,
'rateLimit': 3000,
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
'signIn': true,
},
'urls': {
@@ -29931,8 +38838,10 @@ module.exports = class btctradeua extends Exchange {
'status': 'open',
'symbol': symbol,
'type': undefined,
+ 'timeInForce': undefined,
'side': this.safeString (order, 'type'),
'price': this.safeFloat (order, 'price'),
+ 'stopPrice': undefined,
'amount': this.safeFloat (order, 'amnt_trade'),
'filled': 0,
'remaining': this.safeFloat (order, 'amnt_trade'),
@@ -29987,7 +38896,7 @@ module.exports = class btctradeua extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],53:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],53:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -30005,15 +38914,22 @@ module.exports = class btcturk extends Exchange {
'countries': [ 'TR' ], // Turkey
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': true,
- 'fetchTickers': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchOHLCV': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'timeframes': {
'1d': '1d',
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27992709-18e15646-64a3-11e7-9fa2-b0950ec7712f.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87153926-efbef500-c2c0-11ea-9842-05b63612c4b9.jpg',
'api': 'https://www.btcturk.com/api',
'www': 'https://www.btcturk.com',
'doc': 'https://github.com/BTCTrader/broker-api-docs',
@@ -30174,7 +39090,7 @@ module.exports = class btcturk extends Exchange {
}
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -30227,10 +39143,9 @@ module.exports = class btcturk extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
- const timestamp = this.parse8601 (this.safeString (ohlcv, 'Time'));
+ parseOHLCV (ohlcv, market = undefined) {
return [
- timestamp,
+ this.parse8601 (this.safeString (ohlcv, 'Time')),
this.safeFloat (ohlcv, 'Open'),
this.safeFloat (ohlcv, 'High'),
this.safeFloat (ohlcv, 'Low'),
@@ -30302,7 +39217,7 @@ module.exports = class btcturk extends Exchange {
headers = {
'X-PCK': this.apiKey,
'X-Stamp': nonce,
- 'X-Signature': this.stringToBase64 (this.hmac (this.encode (auth), secret, 'sha256', 'binary')),
+ 'X-Signature': this.hmac (this.encode (auth), secret, 'sha256', 'base64'),
'Content-Type': 'application/x-www-form-urlencoded',
};
}
@@ -30310,7 +39225,7 @@ module.exports = class btcturk extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],54:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],54:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -30329,19 +39244,25 @@ module.exports = class buda extends Exchange {
'rateLimit': 1000,
'version': 'v2',
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createDepositAddress': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
'fetchFundingFees': true,
+ 'fetchMarkets': true,
'fetchMyTrades': false,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
'fetchOrders': true,
'fetchTrades': true,
+ 'fetchTicker': true,
'fetchWithdrawals': true,
'withdraw': true,
},
@@ -30846,16 +39767,8 @@ module.exports = class buda extends Exchange {
parseOrder (order, market = undefined) {
const id = this.safeString (order, 'id');
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
- let symbol = undefined;
- if (market === undefined) {
- const marketId = order['market_id'];
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'market_id');
+ const symbol = this.safeSymbol (marketId, market);
const type = this.safeString (order, 'price_type');
const side = this.safeStringLower (order, 'type');
const status = this.parseOrderStatus (this.safeString (order, 'state'));
@@ -30883,8 +39796,10 @@ module.exports = class buda extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -31068,7 +39983,7 @@ module.exports = class buda extends Exchange {
const nonce = this.nonce ().toString ();
const components = [ method, '/api/' + this.version + '/' + request ];
if (body) {
- const base64Body = this.stringToBase64 (this.encode (body));
+ const base64Body = this.stringToBase64 (body);
components.push (this.decode (base64Body));
}
components.push (nonce);
@@ -31100,7 +40015,7 @@ module.exports = class buda extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],55:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],55:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -31173,6 +40088,7 @@ module.exports = class bw extends Exchange {
'www': 'https://www.bw.com',
'doc': 'https://github.com/bw-exchange/api_docs_en/wiki',
'fees': 'https://www.bw.com/feesRate',
+ 'referral': 'https://www.bw.com/regGetCommission/N3JuT1R3bWxKTE0',
},
'requiredCredentials': {
'apiKey': true,
@@ -31435,16 +40351,8 @@ module.exports = class bw extends Exchange {
// "469849357.2364" // quote volume
// ]
//
- let symbol = undefined;
const marketId = this.safeString (ticker, 0);
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.milliseconds ();
const close = parseFloat (this.safeValue (ticker, 1));
const bid = this.safeValue (ticker, 'bid', {});
@@ -31532,7 +40440,7 @@ module.exports = class bw extends Exchange {
result[symbol] = ticker;
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -31660,7 +40568,25 @@ module.exports = class bw extends Exchange {
return this.parseTrades (trades, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // "K",
+ // "305",
+ // "eth_btc",
+ // "1591511280",
+ // "0.02504",
+ // "0.02504",
+ // "0.02504",
+ // "0.02504",
+ // "0.0123",
+ // "0",
+ // "285740.17",
+ // "1M",
+ // "false",
+ // "0.000308"
+ // ]
+ //
return [
this.safeTimestamp (ohlcv, 3),
this.safeFloat (ohlcv, 4),
@@ -31683,9 +40609,18 @@ module.exports = class bw extends Exchange {
request['dataSize'] = limit;
}
const response = await this.publicGetApiDataV1Klines (this.extend (request, params));
+ //
+ // {
+ // "datas":[
+ // ["K","305","eth_btc","1591511280","0.02504","0.02504","0.02504","0.02504","0.0123","0","285740.17","1M","false","0.000308"],
+ // ["K","305","eth_btc","1591511220","0.02504","0.02504","0.02504","0.02504","0.0006","0","285740.17","1M","false","0.00001502"],
+ // ["K","305","eth_btc","1591511100","0.02505","0.02505","0.02504","0.02504","0.0012","-0.0399","285740.17","1M","false","0.00003005"],
+ // ],
+ // "resMsg":{"code":"1","method":null,"message":"success !"}
+ // }
+ //
const data = this.safeValue (response, 'datas', []);
- const ohlcvs = this.parseOHLCVs (data, market, timeframe, since, limit);
- return this.sortBy (ohlcvs, 0);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async fetchBalance (params = {}) {
@@ -31808,9 +40743,7 @@ module.exports = class bw extends Exchange {
// }
//
const marketId = this.safeString (order, 'marketId');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.safeInteger (order, 'createTime');
let side = this.safeString (order, 'type');
if (side === '0') {
@@ -31843,10 +40776,12 @@ module.exports = class bw extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
- 'symbol': this.safeString (market, 'symbol'),
+ 'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': undefined,
@@ -32287,14 +41222,14 @@ module.exports = class bw extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],56:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],56:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { TICK_SIZE } = require ('./base/functions/number');
-const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce, NotSupported } = require ('./base/errors');
+const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -32308,27 +41243,29 @@ module.exports = class bybit extends Exchange {
'userAgent': undefined,
'rateLimit': 100,
'has': {
+ 'cancelOrder': true,
'CORS': true,
- 'fetchMarkets': true,
- 'fetchBalance': true,
- 'fetchOHLCV': true,
+ 'cancelAllOrders': true,
+ 'createOrder': true,
'editOrder': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchOrderTrades': true,
'fetchTicker': true,
'fetchTickers': true,
- 'fetchOrderTrades': true,
- 'createOrder': true,
- 'cancelOrder': true,
- 'cancelAllOrders': true,
'fetchTime': true,
- 'fetchWithdrawals': true,
- 'fetchDeposits': false,
+ 'fetchTrades': true,
'fetchTransactions': false,
- 'fetchLedger': true,
+ 'fetchWithdrawals': true,
},
'timeframes': {
'1m': '1',
@@ -32350,7 +41287,7 @@ module.exports = class bybit extends Exchange {
'test': 'https://api-testnet.bybit.com',
'logo': 'https://user-images.githubusercontent.com/51840849/76547799-daff5b80-649e-11ea-87fb-3be9bac08954.jpg',
'api': 'https://api.bybit.com',
- 'www': 'https://www.bybit.com/',
+ 'www': 'https://www.bybit.com',
'doc': [
'https://bybit-exchange.github.io/docs/inverse/',
'https://bybit-exchange.github.io/docs/linear/',
@@ -32367,31 +41304,44 @@ module.exports = class bybit extends Exchange {
'tickers',
'trading-records',
'symbols',
+ 'liq-records',
+ 'mark-price-kline',
+ 'open-interest',
+ 'big-deal',
+ 'account-ratio',
'time',
'announcement',
],
},
'private': {
'get': [
+ 'order/list',
'order',
+ 'stop-order/list',
'stop-order',
'position/list',
'wallet/balance',
'execution/list',
+ 'trade/closed-pnl/list',
+ 'account/lcp',
+ 'exchange-order/list',
],
'post': [
'order/create',
'order/cancel',
'order/cancelAll',
+ 'order/replace',
+ 'stop-order/create',
+ 'stop-order/cancel',
'stop-order/cancelAll',
+ 'stop-order/replace',
],
},
'openapi': {
'get': [
- 'order/list',
- 'stop-order/list',
+ 'order/list', // deprecated
+ 'stop-order/list', // deprecated
'wallet/risk-limit/list',
- 'wallet/risk-limit',
'funding/prev-funding-rate',
'funding/prev-funding',
'funding/predicted-funding',
@@ -32400,11 +41350,12 @@ module.exports = class bybit extends Exchange {
'wallet/withdraw/list',
],
'post': [
- 'order/replace',
- 'stop-order/create',
- 'stop-order/cancel',
- 'stop-order/replace',
+ 'order/replace', // deprecated
+ 'stop-order/create', // deprecated
+ 'stop-order/cancel', // deprecated
+ 'stop-order/replace', // deprecated
'position/trading-stop',
+ 'wallet/risk-limit',
],
},
'publicLinear': {
@@ -32413,6 +41364,7 @@ module.exports = class bybit extends Exchange {
'recent-trading-records',
'funding/prev-funding-rate',
'mark-price-kline',
+ 'risk-limit',
],
},
'privateLinear': {
@@ -32422,24 +41374,26 @@ module.exports = class bybit extends Exchange {
'stop-order/list',
'stop-order/search',
'position/list',
- 'position/set-auto-add-margin',
- 'position/set-leverage',
- 'position/switch-isolated',
- 'position/trading-stop',
- 'position/add-margin',
'trade/execution/list',
'trade/closed-pnl/list',
- 'risk-limit',
'funding/prev-funding',
'funding/predicted-funding',
],
'post': [
'order/create',
'order/cancel',
- 'order/cancelAll',
+ 'order/cancel-all',
+ 'order/replace',
'stop-order/create',
'stop-order/cancel',
- 'stop-order/cancelAll',
+ 'stop-order/cancel-all',
+ 'stop-order/replace',
+ 'position/switch-isolated',
+ 'position/set-auto-add-margin',
+ 'tpsl/switch-mode',
+ 'position/set-leverage',
+ 'position/trading-stop',
+ 'position/add-margin',
],
},
'position': {
@@ -32449,7 +41403,7 @@ module.exports = class bybit extends Exchange {
},
'user': {
'get': [
- 'leverage',
+ 'leverage', // deprecated
],
'post': [
'leverage/save',
@@ -32549,17 +41503,19 @@ module.exports = class bybit extends Exchange {
},
'broad': {
'unknown orderInfo': OrderNotFound, // {"ret_code":-1,"ret_msg":"unknown orderInfo","ext_code":"","ext_info":"","result":null,"time_now":"1584030414.005545","rate_limit_status":99,"rate_limit_reset_ms":1584030414003,"rate_limit":100}
+ 'invalid api_key': AuthenticationError, // {"ret_code":10003,"ret_msg":"invalid api_key","ext_code":"","ext_info":"","result":null,"time_now":"1599547085.415797"}
},
},
'precisionMode': TICK_SIZE,
'options': {
'marketTypes': {
'BTC/USDT': 'linear',
+ 'ETH/USDT': 'linear',
+ 'LTC/USDT': 'linear',
+ 'XTZ/USDT': 'linear',
+ 'LINK/USDT': 'linear',
},
'code': 'BTC',
- 'fetchBalance': {
- 'code': 'BTC',
- },
'cancelAllOrders': {
'method': 'privatePostOrderCancelAll', // privatePostStopOrderCancelAll
},
@@ -32588,8 +41544,8 @@ module.exports = class bybit extends Exchange {
return this.milliseconds () - this.options['timeDifference'];
}
- async loadTimeDifference () {
- const serverTime = await this.fetchTime ();
+ async loadTimeDifference (params = {}) {
+ const serverTime = await this.fetchTime (params);
const after = this.milliseconds ();
this.options['timeDifference'] = after - serverTime;
return this.options['timeDifference'];
@@ -32637,32 +41593,66 @@ module.exports = class bybit extends Exchange {
// time_now: '1583930495.454196'
// }
//
+ // sandbox/testnet
+ //
+ // {
+ // "ret_code":0,
+ // "ret_msg":"OK",
+ // "ext_code":"",
+ // "ext_info":"",
+ // "result":[
+ // {
+ // "symbol":"BTCUSD",
+ // "symbol_alias":"BTCUSD",
+ // "status":"Trading",
+ // "base_currency":"BTC",
+ // "quote_currency":"USD",
+ // "price_scale":2,
+ // "taker_fee":"0.00075",
+ // "maker_fee":"-0.00025",
+ // "leverage_filter":{"min_leverage":1,"max_leverage":100,"leverage_step":"0.01"},
+ // "price_filter":{"min_price":"0.5","max_price":"999999.5","tick_size":"0.5"},
+ // "lot_size_filter":{"max_trading_qty":1000000,"min_trading_qty":1,"qty_step":1}
+ // }
+ // ],
+ // "time_now":"1605916574.118500"
+ // }
+ //
const markets = this.safeValue (response, 'result', []);
const options = this.safeValue (this.options, 'fetchMarkets', {});
const linearQuoteCurrencies = this.safeValue (options, 'linear', { 'USDT': true });
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
- const id = this.safeString (market, 'name');
+ const id = this.safeString2 (market, 'name', 'symbol');
const baseId = this.safeString (market, 'base_currency');
const quoteId = this.safeString (market, 'quote_currency');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const linear = (quote in linearQuoteCurrencies);
const inverse = !linear;
- const symbol = base + '/' + quote;
+ let symbol = base + '/' + quote;
+ const baseQuote = base + quote;
+ if (baseQuote !== id) {
+ symbol = id;
+ }
const lotSizeFilter = this.safeValue (market, 'lot_size_filter', {});
const priceFilter = this.safeValue (market, 'price_filter', {});
const precision = {
'amount': this.safeFloat (lotSizeFilter, 'qty_step'),
'price': this.safeFloat (priceFilter, 'tick_size'),
};
+ const status = this.safeString (market, 'status');
+ let active = undefined;
+ if (status !== undefined) {
+ active = (status === 'Trading');
+ }
result.push ({
'id': id,
'symbol': symbol,
'base': base,
'quote': quote,
- 'active': undefined,
+ 'active': active,
'precision': precision,
'taker': this.safeFloat (market, 'taker_fee'),
'maker': this.safeFloat (market, 'maker_fee'),
@@ -32694,13 +41684,15 @@ module.exports = class bybit extends Exchange {
async fetchBalance (params = {}) {
await this.loadMarkets ();
- const defaultCode = this.safeValue (this.options, 'code', 'BTC');
- const options = this.safeValue (this.options, 'fetchBalance', {});
- const code = this.safeValue (options, 'code', defaultCode);
- const currency = this.currency (code);
- const request = {
- 'coin': currency['id'],
- };
+ const request = {};
+ const coin = this.safeString (params, 'coin');
+ const code = this.safeString (params, 'code');
+ if (coin !== undefined) {
+ request['coin'] = coin;
+ } else if (code !== undefined) {
+ const currency = this.currency (code);
+ request['coin'] = currency['id'];
+ }
const response = await this.privateGetWalletBalance (this.extend (request, params));
//
// {
@@ -32781,13 +41773,7 @@ module.exports = class bybit extends Exchange {
//
const timestamp = undefined;
const marketId = this.safeString (ticker, 'symbol');
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const last = this.safeFloat (ticker, 'last_price');
const open = this.safeFloat (ticker, 'prev_price_24h');
let percentage = this.safeFloat (ticker, 'price_24h_pcnt');
@@ -32802,10 +41788,7 @@ module.exports = class bybit extends Exchange {
}
const baseVolume = this.safeFloat (ticker, 'turnover_24h');
const quoteVolume = this.safeFloat (ticker, 'volume_24h');
- let vwap = undefined;
- if (quoteVolume !== undefined && baseVolume !== undefined) {
- vwap = quoteVolume / baseVolume;
- }
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -32931,7 +41914,9 @@ module.exports = class bybit extends Exchange {
return this.filterByArray (tickers, 'symbol', symbols);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // inverse perpetual BTC/USD
//
// {
// symbol: 'BTCUSD',
@@ -32943,7 +41928,9 @@ module.exports = class bybit extends Exchange {
// close: '7763.5',
// volume: '1259766',
// turnover: '162.32773718999994'
- // },
+ // }
+ //
+ // linear perpetual BTC/USDT
//
// {
// "id":143536,
@@ -33086,30 +42073,12 @@ module.exports = class bybit extends Exchange {
// }
//
const id = this.safeString2 (trade, 'id', 'exec_id');
- let symbol = undefined;
- let base = undefined;
const marketId = this.safeString (trade, 'symbol');
- let amount = this.safeFloat2 (trade, 'qty', 'exec_qty');
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
+ const amount = this.safeFloat2 (trade, 'qty', 'exec_qty');
let cost = this.safeFloat (trade, 'exec_value');
- const price = this.safeFloat2 (trade, 'price', 'exec_price');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- base = market['base'];
- }
- if (market !== undefined) {
- if (symbol === undefined) {
- symbol = market['symbol'];
- base = market['base'];
- }
- // if private trade
- if ('exec_fee' in trade) {
- if (market['inverse']) {
- amount = this.safeFloat (trade, 'exec_value');
- cost = this.safeFloat (trade, 'exec_qty');
- }
- }
- }
+ const price = this.safeFloat2 (trade, 'exec_price', 'price');
if (cost === undefined) {
if (amount !== undefined) {
if (price !== undefined) {
@@ -33127,9 +42096,10 @@ module.exports = class bybit extends Exchange {
const feeCost = this.safeFloat (trade, 'exec_fee');
let fee = undefined;
if (feeCost !== undefined) {
+ const feeCurrencyCode = market['inverse'] ? market['base'] : market['quote'];
fee = {
'cost': feeCost,
- 'currency': base,
+ 'currency': feeCurrencyCode,
'rate': this.safeFloat (trade, 'fee_rate'),
};
}
@@ -33246,11 +42216,11 @@ module.exports = class bybit extends Exchange {
'Rejected': 'rejected', // order is triggered but failed upon being placed
'New': 'open',
'PartiallyFilled': 'open',
- 'Filled': 'filled',
+ 'Filled': 'closed',
'Cancelled': 'canceled',
'PendingCancel': 'canceling', // the engine has received the cancellation but there is no guarantee that it will be successful
// conditional orders
- 'Active': 'closed', // order is triggered and placed successfully
+ 'Active': 'open', // order is triggered and placed successfully
'Untriggered': 'open', // order waits to be triggered
'Triggered': 'closed', // order is triggered
// 'Cancelled': 'canceled', // order is cancelled
@@ -33260,6 +42230,16 @@ module.exports = class bybit extends Exchange {
return this.safeString (statuses, status, status);
}
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'GoodTillCancel': 'GTC',
+ 'ImmediateOrCancel': 'IOC',
+ 'FillOrKill': 'FOK',
+ 'PostOnly': 'PO',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
+ }
+
parseOrder (order, market = undefined) {
//
// createOrder
@@ -33316,34 +42296,60 @@ module.exports = class bybit extends Exchange {
// "order_id" : "dd2504b9-0157-406a-99e1-efa522373944"
// }
//
+ // conditional order
+ //
+ // {
+ // "user_id":##,
+ // "symbol":"BTCUSD",
+ // "side":"Buy",
+ // "order_type":"Market",
+ // "price":0,
+ // "qty":10,
+ // "time_in_force":"GoodTillCancel",
+ // "stop_order_type":"Stop",
+ // "trigger_by":"LastPrice",
+ // "base_price":11833,
+ // "order_status":"Untriggered",
+ // "ext_fields":{
+ // "stop_order_type":"Stop",
+ // "trigger_by":"LastPrice",
+ // "base_price":11833,
+ // "expected_direction":"Rising",
+ // "trigger_price":12400,
+ // "close_on_trigger":true,
+ // "op_from":"api",
+ // "remark":"145.53.159.48",
+ // "o_req_num":0
+ // },
+ // "leaves_qty":10,
+ // "leaves_value":0.00080645,
+ // "reject_reason":null,
+ // "cross_seq":-1,
+ // "created_at":"2020-08-21T09:18:48.000Z",
+ // "updated_at":"2020-08-21T09:18:48.000Z",
+ // "stop_px":12400,
+ // "stop_order_id":"3f3b54b1-3379-42c7-8510-44f4d9915be0"
+ // }
+ //
const marketId = this.safeString (order, 'symbol');
+ market = this.safeMarket (marketId, market);
let symbol = undefined;
let base = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
- const id = this.safeString (order, 'order_id');
- const price = this.safeFloat (order, 'price');
- const average = this.safeFloat (order, 'average_price');
- let amount = undefined;
- let cost = undefined;
- let filled = undefined;
- let remaining = undefined;
+ const id = this.safeString2 (order, 'order_id', 'stop_order_id');
+ const type = this.safeStringLower (order, 'order_type');
+ let price = this.safeFloat (order, 'price');
+ if (price === 0.0) {
+ price = undefined;
+ }
+ let average = this.safeFloat (order, 'average_price');
+ const amount = this.safeFloat (order, 'qty');
+ let cost = this.safeFloat (order, 'cum_exec_value');
+ let filled = this.safeFloat (order, 'cum_exec_qty');
+ let remaining = this.safeFloat (order, 'leaves_qty');
if (market !== undefined) {
symbol = market['symbol'];
base = market['base'];
- if (market['inverse']) {
- cost = this.safeFloat (order, 'cum_exec_qty');
- filled = this.safeFloat (order, 'cum_exec_value');
- remaining = this.safeFloat (order, 'leaves_value');
- amount = this.sum (filled, remaining);
- } else {
- amount = this.safeFloat (order, 'qty');
- cost = this.safeFloat (order, 'cum_exec_value');
- filled = this.safeFloat (order, 'cum_exec_qty');
- remaining = this.safeFloat (order, 'leaves_qty');
- }
}
let lastTradeTimestamp = this.safeTimestamp (order, 'last_exec_time');
if (lastTradeTimestamp === 0) {
@@ -33361,8 +42367,14 @@ module.exports = class bybit extends Exchange {
cost = price * filled;
}
}
+ if ((type === 'market') && (cost !== undefined) && (cost > 0)) {
+ price = undefined;
+ if (average === undefined) {
+ average = filled / cost;
+ }
+ }
}
- const status = this.parseOrderStatus (this.safeString (order, 'order_status'));
+ const status = this.parseOrderStatus (this.safeString2 (order, 'order_status', 'stop_order_status'));
const side = this.safeStringLower (order, 'side');
let feeCost = this.safeFloat (order, 'cum_exec_fee');
let fee = undefined;
@@ -33373,11 +42385,12 @@ module.exports = class bybit extends Exchange {
'currency': base,
};
}
- const type = this.safeStringLower (order, 'order_type');
let clientOrderId = this.safeString (order, 'order_link_id');
if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
clientOrderId = undefined;
}
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'time_in_force'));
+ const stopPrice = this.safeFloat (order, 'stop_px');
return {
'info': order,
'id': id,
@@ -33387,8 +42400,10 @@ module.exports = class bybit extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -33499,20 +42514,26 @@ module.exports = class bybit extends Exchange {
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
+ let qty = this.amountToPrecision (symbol, amount);
+ if (market['inverse']) {
+ qty = parseInt (qty);
+ } else {
+ qty = parseFloat (qty);
+ }
const request = {
// orders ---------------------------------------------------------
'side': this.capitalize (side),
'symbol': market['id'],
'order_type': this.capitalize (type),
- 'qty': this.amountToPrecision (symbol, amount), // order quantity in USD, integer only
- // 'price': this.priceToPrecision (symbol, price), // required for limit orders
+ 'qty': qty, // order quantity in USD, integer only
+ // 'price': parseFloat (this.priceToPrecision (symbol, price)), // required for limit orders
'time_in_force': 'GoodTillCancel', // ImmediateOrCancel, FillOrKill, PostOnly
// 'take_profit': 123.45, // take profit price, only take effect upon opening the position
// 'stop_loss': 123.45, // stop loss price, only take effect upon opening the position
- // 'reduce_only': false, // reduce only
+ // 'reduce_only': false, // reduce only, required for linear orders
// when creating a closing order, bybit recommends a True value for
// close_on_trigger to avoid failing due to insufficient available margin
- // 'close_on_trigger': false,
+ // 'close_on_trigger': false, required for linear orders
// 'order_link_id': 'string', // unique client order id, max 36 characters
// conditional orders ---------------------------------------------
// base_price is used to compare with the value of stop_px, to decide
@@ -33529,24 +42550,34 @@ module.exports = class bybit extends Exchange {
}
if (priceIsRequired) {
if (price !== undefined) {
- request['price'] = this.priceToPrecision (symbol, price);
+ request['price'] = parseFloat (this.priceToPrecision (symbol, price));
} else {
throw new ArgumentsRequired (this.id + ' createOrder requires a price argument for a ' + type + ' order');
}
}
- const stopPx = this.safeValue (params, 'stop_px');
+ const clientOrderId = this.safeString2 (params, 'order_link_id', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['order_link_id'] = clientOrderId;
+ params = this.omit (params, [ 'order_link_id', 'clientOrderId' ]);
+ }
+ const stopPx = this.safeValue2 (params, 'stop_px', 'stopPrice');
const basePrice = this.safeValue (params, 'base_price');
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
let method = (marketType === 'linear') ? 'privateLinearPostOrderCreate' : 'privatePostOrderCreate';
+ if (marketType === 'linear') {
+ method = 'privateLinearPostOrderCreate';
+ request['reduce_only'] = false;
+ request['close_on_trigger'] = false;
+ }
if (stopPx !== undefined) {
if (basePrice === undefined) {
throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order');
} else {
method = (marketType === 'linear') ? 'privateLinearPostStopOrderCreate' : 'openapiPostStopOrderCreate';
- request['stop_px'] = this.priceToPrecision (symbol, stopPx);
- request['base_price'] = this.priceToPrecision (symbol, basePrice);
- params = this.omit (params, [ 'stop_px', 'base_price' ]);
+ request['stop_px'] = parseFloat (this.priceToPrecision (symbol, stopPx));
+ request['base_price'] = parseFloat (this.priceToPrecision (symbol, basePrice));
+ params = this.omit (params, [ 'stop_px', 'stopPrice', 'base_price' ]);
}
} else if (basePrice !== undefined) {
throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order');
@@ -33639,9 +42670,6 @@ module.exports = class bybit extends Exchange {
}
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
- if (marketType === 'linear') {
- throw new NotSupported (this.id + ' does not support editOrder for ' + marketType + ' ' + symbol + ' market type');
- }
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
@@ -33654,20 +42682,20 @@ module.exports = class bybit extends Exchange {
// 'stop_order_id': id, // only for conditional orders
// 'p_r_trigger_price': 123.45, // new trigger price also known as stop_px
};
+ let method = (marketType === 'linear') ? 'privateLinearPostOrderReplace' : 'openapiPostOrderReplace';
const stopOrderId = this.safeString (params, 'stop_order_id');
- let method = 'openapiPostOrderReplace';
if (stopOrderId !== undefined) {
- method = 'openapiPostStopOrderReplace';
+ method = (marketType === 'linear') ? 'privateLinearPostStopOrderReplace' : 'openapiPostStopOrderReplace';
request['stop_order_id'] = stopOrderId;
params = this.omit (params, [ 'stop_order_id' ]);
} else {
request['order_id'] = id;
}
if (amount !== undefined) {
- request['p_r_qty'] = this.amountToPrecision (symbol, amount);
+ request['p_r_qty'] = parseInt (this.amountToPrecision (symbol, amount));
}
if (price !== undefined) {
- request['p_r_price'] = this.priceToPrecision (symbol, price);
+ request['p_r_price'] = parseFloat (this.priceToPrecision (symbol, price));
}
const response = await this[method] (this.extend (request, params));
//
@@ -33707,7 +42735,7 @@ module.exports = class bybit extends Exchange {
async cancelOrder (id, symbol = undefined, params = {}) {
if (symbol === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
@@ -33977,6 +43005,8 @@ module.exports = class bybit extends Exchange {
const method = (marketType === 'linear') ? 'privateLinearGetTradeExecutionList' : 'privateGetExecutionList';
const response = await this[method] (this.extend (request, params));
//
+ // inverse
+ //
// {
// "ret_code": 0,
// "ret_msg": "OK",
@@ -34016,8 +43046,48 @@ module.exports = class bybit extends Exchange {
// "rate_limit": 120
// }
//
+ // linear
+ //
+ // {
+ // "ret_code":0,
+ // "ret_msg":"OK",
+ // "ext_code":"",
+ // "ext_info":"",
+ // "result":{
+ // "current_page":1,
+ // "data":[
+ // {
+ // "order_id":"b59418ec-14d4-4ef9-b9f4-721d5d576974",
+ // "order_link_id":"",
+ // "side":"Sell",
+ // "symbol":"BTCUSDT",
+ // "exec_id":"0327284d-faec-5191-bd89-acc5b4fafda9",
+ // "price":0.5,
+ // "order_price":0.5,
+ // "order_qty":0.01,
+ // "order_type":"Market",
+ // "fee_rate":0.00075,
+ // "exec_price":9709.5,
+ // "exec_type":"Trade",
+ // "exec_qty":0.01,
+ // "exec_fee":0.07282125,
+ // "exec_value":97.095,
+ // "leaves_qty":0,
+ // "closed_size":0.01,
+ // "last_liquidity_ind":"RemovedLiquidity",
+ // "trade_time":1591648052,
+ // "trade_time_ms":1591648052861
+ // }
+ // ]
+ // },
+ // "time_now":"1591736501.979264",
+ // "rate_limit_status":119,
+ // "rate_limit_reset_ms":1591736501974,
+ // "rate_limit":120
+ // }
+ //
const result = this.safeValue (response, 'result', {});
- const trades = this.safeValue (result, 'trade_list', []);
+ const trades = this.safeValue2 (result, 'trade_list', 'data', []);
return this.parseTrades (trades, market, since, limit);
}
@@ -34334,7 +43404,13 @@ module.exports = class bybit extends Exchange {
'recv_window': this.options['recvWindow'],
'timestamp': timestamp,
});
- const auth = this.rawencode (this.keysort (query));
+ let auth = this.rawencode (this.keysort (query));
+ // https://github.com/ccxt/ccxt/issues/7377
+ // https://github.com/ccxt/ccxt/issues/7515
+ // bybit encodes whole floats as integers without .0 for conditional stop-orders only
+ if (path.indexOf ('stop-order') >= 0) {
+ auth = auth.replace ('.0&', '&');
+ }
const signature = this.hmac (this.encode (auth), this.encode (this.secret));
if (method === 'POST') {
body = this.json (this.extend (query, {
@@ -34377,7 +43453,7 @@ module.exports = class bybit extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],57:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],57:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -34399,20 +43475,27 @@ module.exports = class bytetrade extends Exchange {
'certified': true,
// new metainfo interface
'has': {
+ 'cancelOrder': true,
+ 'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchBidsAsks': true,
+ 'fetchClosedOrders': true,
'fetchCurrencies': true,
'fetchDepositAddress': true,
- 'CORS': false,
- 'fetchBidsAsks': true,
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchMyTrades': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'withdraw': true,
'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1m',
@@ -34433,11 +43516,11 @@ module.exports = class bytetrade extends Exchange {
},
'logo': 'https://user-images.githubusercontent.com/1294454/67288762-2f04a600-f4e6-11e9-9fd6-c60641919491.jpg',
'api': {
- 'market': 'https://api-v2.bytetrade.com',
- 'public': 'https://api-v2.bytetrade.com',
+ 'market': 'https://api-v2.byte-trade.com',
+ 'public': 'https://api-v2.byte-trade.com',
},
'www': 'https://www.byte-trade.com',
- 'doc': 'https://github.com/Bytetrade/bytetrade-official-api-docs/wiki',
+ 'doc': 'https://docs.byte-trade.com/#description',
},
'api': {
'market': {
@@ -34478,8 +43561,10 @@ module.exports = class bytetrade extends Exchange {
},
},
'commonCurrencies': {
+ '1': 'ByteTrade',
'44': 'ByteHub',
'48': 'Blocktonic',
+ '133': 'TerraCredit',
},
'exceptions': {
'vertify error': AuthenticationError, // typo on the exchange side, 'vertify'
@@ -34571,10 +43656,7 @@ module.exports = class bytetrade extends Exchange {
'code': code,
'name': name,
'active': active,
- 'precision': {
- 'amount': amountPrecision,
- 'price': undefined,
- },
+ 'precision': amountPrecision,
'fee': undefined,
'limits': {
'amount': { 'min': undefined, 'max': undefined },
@@ -34603,11 +43685,14 @@ module.exports = class bytetrade extends Exchange {
const id = this.safeString (market, 'symbol');
let base = this.safeString (market, 'baseName');
let quote = this.safeString (market, 'quoteName');
- const normalBase = base.split ('@')[0];
- const normalQuote = quote.split ('@')[0];
- const normalSymbol = normalBase + '/' + normalQuote;
const baseId = this.safeString (market, 'base');
const quoteId = this.safeString (market, 'quote');
+ const normalBase = base.split ('@' + baseId)[0];
+ let normalQuote = quote.split ('@' + quoteId)[0];
+ if (quoteId === '126') {
+ normalQuote = 'ZAR'; // The id 126 coin is a special coin whose name on the chain is actually ZAR, but it is changed to ZCN after creation, so it must be changed to ZAR when placing the transaction in the chain
+ }
+ const normalSymbol = normalBase + '/' + normalQuote;
if (baseId in this.commonCurrencies) {
base = this.commonCurrencies[baseId];
}
@@ -34812,14 +43897,24 @@ module.exports = class bytetrade extends Exchange {
return this.parseTickers (rawTickers, symbols);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591505760000,
+ // "242.7",
+ // "242.76",
+ // "242.69",
+ // "242.76",
+ // "0.1892"
+ // ]
+ //
return [
- ohlcv[0],
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
- parseFloat (ohlcv[5]),
+ this.safeInteger (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -34837,6 +43932,13 @@ module.exports = class bytetrade extends Exchange {
request['limit'] = limit;
}
const response = await this.marketGetKlines (this.extend (request, params));
+ //
+ // [
+ // [1591505760000,"242.7","242.76","242.69","242.76","0.1892"],
+ // [1591505820000,"242.77","242.83","242.7","242.72","0.6378"],
+ // [1591505880000,"242.72","242.73","242.61","242.72","0.4141"],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -34849,7 +43951,7 @@ module.exports = class bytetrade extends Exchange {
const type = this.safeString (trade, 'type');
const takerOrMaker = this.safeString (trade, 'takerOrMaker');
const side = this.safeString (trade, 'side');
- const datetime = this.safeString (trade, 'datetime');
+ const datetime = this.iso8601 (timestamp); // this.safeString (trade, 'datetime');
const order = this.safeString (trade, 'order');
const fee = this.safeValue (trade, 'fee');
let symbol = undefined;
@@ -34933,8 +44035,10 @@ module.exports = class bytetrade extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': average,
@@ -34970,11 +44074,11 @@ module.exports = class bytetrade extends Exchange {
const baseId = market['baseId'];
const baseCurrency = this.currency (market['base']);
const amountTruncated = this.amountToPrecision (symbol, amount);
- const amountChain = this.toWei (amountTruncated, baseCurrency['precision']['amount']);
+ const amountChain = this.toWei (amountTruncated, baseCurrency['precision']);
const quoteId = market['quoteId'];
const quoteCurrency = this.currency (market['quote']);
const priceRounded = this.priceToPrecision (symbol, price);
- const priceChain = this.toWei (priceRounded, quoteCurrency['precision']['amount']);
+ const priceChain = this.toWei (priceRounded, quoteCurrency['precision']);
const now = this.milliseconds ();
const expiration = this.milliseconds ();
let datetime = this.iso8601 (now);
@@ -34984,6 +44088,8 @@ module.exports = class bytetrade extends Exchange {
const defaultDappId = 'Sagittarius';
const dappId = this.safeString (params, 'dappId', defaultDappId);
const defaultFee = this.safeString (this.options, 'fee', '300000000000000');
+ const totalFeeRate = this.safeString (params, 'totalFeeRate', 8);
+ const chainFeeRate = this.safeString (params, 'chainFeeRate', 1);
const fee = this.safeString (params, 'fee', defaultFee);
const eightBytes = this.integerPow ('2', '64');
const allByteStringArray = [
@@ -35008,7 +44114,10 @@ module.exports = class bytetrade extends Exchange {
this.numberToLE (0, 2),
this.numberToLE (Math.floor (now / 1000), 4),
this.numberToLE (Math.floor (expiration / 1000), 4),
- this.numberToLE (0, 2),
+ this.numberToLE (1, 1),
+ this.numberToLE (parseInt (chainFeeRate), 2),
+ this.numberToLE (1, 1),
+ this.numberToLE (parseInt (totalFeeRate), 2),
this.numberToLE (parseInt (quoteId), 4),
this.numberToLE (parseInt (baseId), 4),
this.numberToLE (0, 1),
@@ -35038,7 +44147,10 @@ module.exports = class bytetrade extends Exchange {
this.numberToLE (0, 2),
this.numberToLE (Math.floor (now / 1000), 4),
this.numberToLE (Math.floor (expiration / 1000), 4),
- this.numberToLE (0, 2),
+ this.numberToLE (1, 1),
+ this.numberToLE (parseInt (chainFeeRate), 2),
+ this.numberToLE (1, 1),
+ this.numberToLE (parseInt (totalFeeRate), 2),
this.numberToLE (parseInt (quoteId), 4),
this.numberToLE (parseInt (baseId), 4),
this.numberToLE (0, 1),
@@ -35061,7 +44173,7 @@ module.exports = class bytetrade extends Exchange {
const bytestring = this.binaryConcatArray (allByteStringArray);
const hash = this.hash (bytestring, 'sha256', 'hex');
const signature = this.ecdsa (hash, this.secret, 'secp256k1', undefined, true);
- const recoveryParam = this.decode (this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1)));
+ const recoveryParam = this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1));
const mySignature = recoveryParam + signature['r'] + signature['s'];
const operation = {
'now': datetime,
@@ -35076,6 +44188,8 @@ module.exports = class bytetrade extends Exchange {
'use_btt_as_fee': false,
'money_id': parseInt (quoteId),
'stock_id': parseInt (baseId),
+ 'custom_no_btt_fee_rate': parseInt (totalFeeRate),
+ 'custom_btt_fee_rate': parseInt (chainFeeRate),
};
const fatty = {
'timestamp': datetime,
@@ -35245,7 +44359,7 @@ module.exports = class bytetrade extends Exchange {
const bytestring = this.binaryConcatArray (byteStringArray);
const hash = this.hash (bytestring, 'sha256', 'hex');
const signature = this.ecdsa (hash, this.secret, 'secp256k1', undefined, true);
- const recoveryParam = this.decode (this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1)));
+ const recoveryParam = this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1));
const mySignature = recoveryParam + signature['r'] + signature['s'];
const operation = {
'fee': feeAmount,
@@ -35306,8 +44420,8 @@ module.exports = class bytetrade extends Exchange {
}
await this.loadMarkets ();
const currency = this.currency (code);
- const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING);
- const amountChain = this.toWei (amountTruncate, currency['precision']['amount']);
+ const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['basePrecision'] - currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING);
+ const amountChain = this.toWei (amountTruncate, currency['precision']);
const assetType = parseInt (currency['id']);
const now = this.milliseconds ();
const expiration = now;
@@ -35347,7 +44461,7 @@ module.exports = class bytetrade extends Exchange {
const bytestring = this.binaryConcatArray (byteStringArray);
const hash = this.hash (bytestring, 'sha256', 'hex');
const signature = this.ecdsa (hash, this.secret, 'secp256k1', undefined, true);
- const recoveryParam = this.decode (this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1)));
+ const recoveryParam = this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1));
const mySignature = recoveryParam + signature['r'] + signature['s'];
const operation = {
'fee': '300000000000000',
@@ -35587,7 +44701,7 @@ module.exports = class bytetrade extends Exchange {
const feeAmount = '300000000000000';
const currency = this.currency (code);
const coinId = currency['id'];
- const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING);
+ const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['basePrecision'] - currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING);
const amountChain = this.toWei (amountTruncate, currency['info']['externalPrecision']);
const eightBytes = this.integerPow ('2', '64');
let assetFee = 0;
@@ -35653,7 +44767,7 @@ module.exports = class bytetrade extends Exchange {
const bytestring = this.binaryConcatArray (byteStringArray);
const hash = this.hash (bytestring, 'sha256', 'hex');
const signature = this.ecdsa (hash, this.secret, 'secp256k1', undefined, true);
- const recoveryParam = this.decode (this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1)));
+ const recoveryParam = this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1));
const mySignature = recoveryParam + signature['r'] + signature['s'];
let fatty = undefined;
let request = undefined;
@@ -35771,13 +44885,13 @@ module.exports = class bytetrade extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],58:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],58:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, AuthenticationError, NullResponse, InvalidOrder, NotSupported, InsufficientFunds, InvalidNonce, OrderNotFound, RateLimitExceeded } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, AuthenticationError, NullResponse, InvalidOrder, NotSupported, InsufficientFunds, InvalidNonce, OrderNotFound, RateLimitExceeded, DDoSProtection } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -35789,15 +44903,23 @@ module.exports = class cex extends Exchange {
'countries': [ 'GB', 'EU', 'CY', 'RU' ],
'rateLimit': 1500,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchCurrencies': true,
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
'fetchDepositAddress': true,
+ 'fetchMarkets': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'timeframes': {
'1m': '1m',
@@ -35899,9 +45021,10 @@ module.exports = class cex extends Exchange {
'Nonce must be incremented': InvalidNonce,
'Invalid Order': InvalidOrder,
'Order not found': OrderNotFound,
- 'Rate limit exceeded': RateLimitExceeded,
+ 'limit exceeded': RateLimitExceeded, // {"error":"rate limit exceeded"}
'Invalid API key': AuthenticationError,
'There was an error while placing your order': InvalidOrder,
+ 'Sorry, too many clients already': DDoSProtection,
},
},
'options': {
@@ -35911,7 +45034,7 @@ module.exports = class cex extends Exchange {
'status': {
'c': 'canceled',
'd': 'closed',
- 'cd': 'closed',
+ 'cd': 'canceled',
'a': 'open',
},
},
@@ -36167,14 +45290,24 @@ module.exports = class cex extends Exchange {
return this.parseOrderBook (response, timestamp);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591403940,
+ // 0.024972,
+ // 0.024972,
+ // 0.024969,
+ // 0.024969,
+ // 0.49999900
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- ohlcv[1],
- ohlcv[2],
- ohlcv[3],
- ohlcv[4],
- ohlcv[5],
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -36197,8 +45330,15 @@ module.exports = class cex extends Exchange {
};
try {
const response = await this.publicGetOhlcvHdYyyymmddPair (this.extend (request, params));
+ //
+ // {
+ // "time":20200606,
+ // "data1m":"[[1591403940,0.024972,0.024972,0.024969,0.024969,0.49999900]]",
+ // }
+ //
const key = 'data' + this.timeframes[timeframe];
- const ohlcvs = JSON.parse (response[key]);
+ const data = this.safeString (response, key);
+ const ohlcvs = JSON.parse (data);
return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
} catch (e) {
if (e instanceof NullResponse) {
@@ -36258,7 +45398,7 @@ module.exports = class cex extends Exchange {
const market = this.markets[symbol];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -36630,8 +45770,10 @@ module.exports = class cex extends Exchange {
'status': status,
'symbol': symbol,
'type': (price === undefined) ? 'market' : 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -36678,7 +45820,108 @@ module.exports = class cex extends Exchange {
'id': id.toString (),
};
const response = await this.privatePostGetOrderTx (this.extend (request, params));
- return this.parseOrder (response['data']);
+ const data = this.safeValue (response, 'data', {});
+ //
+ // {
+ // "id": "5442731603",
+ // "type": "sell",
+ // "time": 1516132358071,
+ // "lastTxTime": 1516132378452,
+ // "lastTx": "5442734452",
+ // "pos": null,
+ // "user": "up106404164",
+ // "status": "d",
+ // "symbol1": "ETH",
+ // "symbol2": "EUR",
+ // "amount": "0.50000000",
+ // "kind": "api",
+ // "price": "923.3386",
+ // "tfacf": "1",
+ // "fa:EUR": "0.55",
+ // "ta:EUR": "369.77",
+ // "remains": "0.00000000",
+ // "tfa:EUR": "0.22",
+ // "tta:EUR": "91.95",
+ // "a:ETH:cds": "0.50000000",
+ // "a:EUR:cds": "461.72",
+ // "f:EUR:cds": "0.77",
+ // "tradingFeeMaker": "0.15",
+ // "tradingFeeTaker": "0.23",
+ // "tradingFeeStrategy": "userVolumeAmount",
+ // "tradingFeeUserVolumeAmount": "2896912572",
+ // "orderId": "5442731603",
+ // "next": false,
+ // "vtx": [
+ // {
+ // "id": "5442734452",
+ // "type": "sell",
+ // "time": "2018-01-16T19:52:58.452Z",
+ // "user": "up106404164",
+ // "c": "user:up106404164:a:EUR",
+ // "d": "order:5442731603:a:EUR",
+ // "a": "104.53000000",
+ // "amount": "104.53000000",
+ // "balance": "932.71000000",
+ // "symbol": "EUR",
+ // "order": "5442731603",
+ // "buy": "5442734443",
+ // "sell": "5442731603",
+ // "pair": null,
+ // "pos": null,
+ // "office": null,
+ // "cs": "932.71",
+ // "ds": 0,
+ // "price": 923.3386,
+ // "symbol2": "ETH",
+ // "fee_amount": "0.16"
+ // },
+ // {
+ // "id": "5442731609",
+ // "type": "sell",
+ // "time": "2018-01-16T19:52:38.071Z",
+ // "user": "up106404164",
+ // "c": "user:up106404164:a:EUR",
+ // "d": "order:5442731603:a:EUR",
+ // "a": "91.73000000",
+ // "amount": "91.73000000",
+ // "balance": "563.49000000",
+ // "symbol": "EUR",
+ // "order": "5442731603",
+ // "buy": "5442618127",
+ // "sell": "5442731603",
+ // "pair": null,
+ // "pos": null,
+ // "office": null,
+ // "cs": "563.49",
+ // "ds": 0,
+ // "price": 924.0092,
+ // "symbol2": "ETH",
+ // "fee_amount": "0.22"
+ // },
+ // {
+ // "id": "5442731604",
+ // "type": "sell",
+ // "time": "2018-01-16T19:52:38.071Z",
+ // "user": "up106404164",
+ // "c": "order:5442731603:a:ETH",
+ // "d": "user:up106404164:a:ETH",
+ // "a": "0.50000000",
+ // "amount": "-0.50000000",
+ // "balance": "15.80995000",
+ // "symbol": "ETH",
+ // "order": "5442731603",
+ // "buy": null,
+ // "sell": null,
+ // "pair": null,
+ // "pos": null,
+ // "office": null,
+ // "cs": "0.50000000",
+ // "ds": "15.80995000"
+ // }
+ // ]
+ // }
+ //
+ return this.parseOrder (data);
}
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -36992,7 +46235,7 @@ module.exports = class cex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],59:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],59:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -37170,6 +46413,9 @@ module.exports = class coinbase extends Exchange {
'rate_limit_exceeded': RateLimitExceeded, // 429 Rate limit exceeded
'internal_server_error': ExchangeError, // 500 Internal server error
},
+ 'commonCurrencies': {
+ 'CGLD': 'CELO',
+ },
'options': {
'fetchCurrencies': {
'expires': 5000,
@@ -37185,8 +46431,16 @@ module.exports = class coinbase extends Exchange {
async fetchTime (params = {}) {
const response = await this.publicGetTime (params);
+ //
+ // {
+ // "data": {
+ // "epoch": 1589295679,
+ // "iso": "2020-05-12T15:01:19Z"
+ // }
+ // }
+ //
const data = this.safeValue (response, 'data', {});
- return this.parse8601 (this.safeString (data, 'iso'));
+ return this.safeTimestamp (data, 'epoch');
}
async fetchAccounts (params = {}) {
@@ -37488,8 +46742,8 @@ module.exports = class coinbase extends Exchange {
const id = this.safeString (trade, 'id');
const timestamp = this.parse8601 (this.safeValue (trade, 'created_at'));
if (market === undefined) {
- const baseId = this.safeString (totalObject, 'currency');
- const quoteId = this.safeString (amountObject, 'currency');
+ const baseId = this.safeString (amountObject, 'currency');
+ const quoteId = this.safeString (totalObject, 'currency');
if ((baseId !== undefined) && (quoteId !== undefined)) {
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
@@ -37503,7 +46757,7 @@ module.exports = class coinbase extends Exchange {
const amount = this.safeFloat (amountObject, 'amount');
let price = undefined;
if (cost !== undefined) {
- if (amount !== undefined) {
+ if ((amount !== undefined) && (amount > 0)) {
price = cost / amount;
}
}
@@ -37751,13 +47005,17 @@ module.exports = class coinbase extends Exchange {
async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
const request = await this.prepareAccountRequestWithCurrencyCode (code, limit, params);
const query = this.omit (params, ['account_id', 'accountId']);
// for pagination use parameter 'starting_after'
// the value for the next page can be obtained from the result of the previous call in the 'pagination' field
// eg: instance.last_json_response.pagination.next_starting_after
const response = await this.privateGetAccountsAccountIdTransactions (this.extend (request, query));
- return this.parseLedger (response['data'], undefined, since, limit);
+ return this.parseLedger (response['data'], currency, since, limit);
}
parseLedgerEntryStatus (status) {
@@ -38213,7 +47471,7 @@ module.exports = class coinbase extends Exchange {
};
-},{"./base/Exchange":7,"./base/errors":9}],61:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],61:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -38252,7 +47510,8 @@ module.exports = class coinbaseprime extends coinbasepro {
// ----------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { InsufficientFunds, ArgumentsRequired, ExchangeError, InvalidOrder, InvalidAddress, AuthenticationError, NotSupported, OrderNotFound, OnMaintenance, RateLimitExceeded } = require ('./base/errors');
+const { InsufficientFunds, ArgumentsRequired, ExchangeError, InvalidOrder, InvalidAddress, AuthenticationError, NotSupported, OrderNotFound, OnMaintenance, PermissionDenied, RateLimitExceeded } = require ('./base/errors');
+const { TICK_SIZE } = require ('./base/functions/number');
// ----------------------------------------------------------------------------
@@ -38267,21 +47526,31 @@ module.exports = class coinbasepro extends Exchange {
'pro': true,
'has': {
'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': true,
+ 'createDepositAddress': true,
+ 'createOrder': true,
'deposit': true,
'fetchAccounts': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': true,
'fetchClosedOrders': true,
- 'fetchDepositAddress': true,
- 'createDepositAddress': true,
+ 'fetchDepositAddress': false, // the exchange does not have this method, only createDepositAddress, see https://github.com/ccxt/ccxt/pull/7405
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
- 'fetchOrderTrades': true,
+ 'fetchOrderBook': true,
'fetchOrders': true,
+ 'fetchOrderTrades': true,
'fetchTime': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
'fetchTransactions': true,
'withdraw': true,
+ 'fetchDeposits': true,
+ 'fetchWithdrawals': true,
},
'timeframes': {
'1m': 60,
@@ -38318,6 +47587,7 @@ module.exports = class coinbasepro extends Exchange {
'get': [
'currencies',
'products',
+ 'products/{id}',
'products/{id}/book',
'products/{id}/candles',
'products/{id}/stats',
@@ -38334,17 +47604,32 @@ module.exports = class coinbasepro extends Exchange {
'accounts/{id}/ledger',
'accounts/{id}/transfers',
'coinbase-accounts',
- 'coinbase-accounts/{id}/addresses',
'fills',
'funding',
'fees',
+ 'margin/profile_information',
+ 'margin/buying_power',
+ 'margin/withdrawal_power',
+ 'margin/withdrawal_power_all',
+ 'margin/exit_plan',
+ 'margin/liquidation_history',
+ 'margin/position_refresh_amounts',
+ 'margin/status',
+ 'oracle',
'orders',
'orders/{id}',
+ 'orders/client:{client_oid}',
'otc/orders',
'payment-methods',
'position',
- 'reports/{id}',
+ 'profiles',
+ 'profiles/{id}',
+ 'reports/{report_id}',
+ 'transfers',
+ 'transfers/{transfer_id}',
'users/self/trailing-volume',
+ 'users/self/exchange-limits',
+ 'withdrawals/fee-estimate',
],
'post': [
'conversions',
@@ -38355,17 +47640,24 @@ module.exports = class coinbasepro extends Exchange {
'orders',
'position/close',
'profiles/margin-transfer',
+ 'profiles/transfer',
'reports',
'withdrawals/coinbase',
+ 'withdrawals/coinbase-account',
'withdrawals/crypto',
'withdrawals/payment-method',
],
'delete': [
'orders',
+ 'orders/client:{client_oid}',
'orders/{id}',
],
},
},
+ 'commonCurrencies': {
+ 'CGLD': 'CELO',
+ },
+ 'precisionMode': TICK_SIZE,
'fees': {
'trading': {
'tierBased': true, // complicated tier system per coin
@@ -38403,6 +47695,8 @@ module.exports = class coinbasepro extends Exchange {
'Invalid Passphrase': AuthenticationError,
'Invalid order id': InvalidOrder,
'Private rate limit exceeded': RateLimitExceeded,
+ 'Trading pair not available': PermissionDenied,
+ 'Product not found': InvalidOrder,
},
'broad': {
'Order already done': OrderNotFound,
@@ -38410,13 +47704,108 @@ module.exports = class coinbasepro extends Exchange {
'price too small': InvalidOrder,
'price too precise': InvalidOrder,
'under maintenance': OnMaintenance,
+ 'size is too small': InvalidOrder,
+ 'Cancel only mode': OnMaintenance, // https://github.com/ccxt/ccxt/issues/7690
},
},
});
}
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCurrencies (params);
+ //
+ // [
+ // {
+ // id: 'XTZ',
+ // name: 'Tezos',
+ // min_size: '0.000001',
+ // status: 'online',
+ // message: '',
+ // max_precision: '0.000001',
+ // convertible_to: [],
+ // details: {
+ // type: 'crypto',
+ // symbol: 'Τ',
+ // network_confirmations: 60,
+ // sort_order: 53,
+ // crypto_address_link: 'https://tzstats.com/{{address}}',
+ // crypto_transaction_link: 'https://tzstats.com/{{txId}}',
+ // push_payment_methods: [ 'crypto' ],
+ // group_types: [],
+ // display_name: '',
+ // processing_time_seconds: 0,
+ // min_withdrawal_amount: 1
+ // }
+ // }
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const currency = response[i];
+ const id = this.safeString (currency, 'id');
+ const name = this.safeString (currency, 'name');
+ const code = this.safeCurrencyCode (id);
+ const details = this.safeValue (currency, 'details', {});
+ const precision = this.safeFloat (currency, 'max_precision');
+ const status = this.safeString (currency, 'status');
+ const active = (status === 'online');
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': currency,
+ 'type': this.safeString (details, 'type'),
+ 'name': name,
+ 'active': active,
+ 'fee': undefined,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': this.safeFloat (details, 'min_size'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (details, 'min_withdrawal_amount'),
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ return result;
+ }
+
async fetchMarkets (params = {}) {
const response = await this.publicGetProducts (params);
+ //
+ // [
+ // {
+ // "id":"ZEC-BTC",
+ // "base_currency":"ZEC",
+ // "quote_currency":"BTC",
+ // "base_min_size":"0.01000000",
+ // "base_max_size":"1500.00000000",
+ // "quote_increment":"0.00000100",
+ // "base_increment":"0.00010000",
+ // "display_name":"ZEC/BTC",
+ // "min_market_funds":"0.001",
+ // "max_market_funds":"30",
+ // "margin_enabled":false,
+ // "post_only":false,
+ // "limit_only":false,
+ // "cancel_only":false,
+ // "trading_disabled":false,
+ // "status":"online",
+ // "status_message":""
+ // }
+ // ]
+ //
const result = [];
for (let i = 0; i < response.length; i++) {
const market = response[i];
@@ -38431,10 +47820,11 @@ module.exports = class coinbasepro extends Exchange {
'max': undefined,
};
const precision = {
- 'amount': this.precisionFromString (this.safeString (market, 'base_increment')),
- 'price': this.precisionFromString (this.safeString (market, 'quote_increment')),
+ 'amount': this.safeFloat (market, 'base_increment'),
+ 'price': this.safeFloat (market, 'quote_increment'),
};
- const active = market['status'] === 'online';
+ const status = this.safeString (market, 'status');
+ const active = (status === 'online');
result.push (this.extend (this.fees['trading'], {
'id': id,
'symbol': symbol,
@@ -38649,21 +48039,8 @@ module.exports = class coinbasepro extends Exchange {
// }
//
const timestamp = this.parse8601 (this.safeString2 (trade, 'time', 'created_at'));
- let symbol = undefined;
const marketId = this.safeString (trade, 'product_id');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
let feeRate = undefined;
let feeCurrency = undefined;
let takerOrMaker = undefined;
@@ -38734,14 +48111,24 @@ module.exports = class coinbasepro extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591514160,
+ // 0.02507,
+ // 0.02507,
+ // 0.02507,
+ // 0.02507,
+ // 0.02816506
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- ohlcv[3],
- ohlcv[2],
- ohlcv[1],
- ohlcv[4],
- ohlcv[5],
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -38762,12 +48149,25 @@ module.exports = class coinbasepro extends Exchange {
request['end'] = this.iso8601 (this.sum ((limit - 1) * granularity * 1000, since));
}
const response = await this.publicGetProductsIdCandles (this.extend (request, params));
+ //
+ // [
+ // [1591514160,0.02507,0.02507,0.02507,0.02507,0.02816506],
+ // [1591514100,0.02507,0.02507,0.02507,0.02507,1.63830323],
+ // [1591514040,0.02505,0.02507,0.02505,0.02507,0.19918178]
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
async fetchTime (params = {}) {
const response = await this.publicGetTime (params);
- return this.parse8601 (this.safeString (response, 'iso'));
+ //
+ // {
+ // "iso":"2020-05-12T08:00:51.504Z",
+ // "epoch":1589270451.504
+ // }
+ //
+ return this.safeTimestamp (response, 'epoch');
}
parseOrderStatus (status) {
@@ -38784,19 +48184,8 @@ module.exports = class coinbasepro extends Exchange {
parseOrder (order, market = undefined) {
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
- let symbol = undefined;
const marketId = this.safeString (order, 'product_id');
- let quote = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
+ market = this.safeMarket (marketId, market, '-');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
const price = this.safeFloat (order, 'price');
const filled = this.safeFloat (order, 'filled_size');
@@ -38814,8 +48203,6 @@ module.exports = class coinbasepro extends Exchange {
let feeCurrencyCode = undefined;
if (market !== undefined) {
feeCurrencyCode = market['quote'];
- } else if (quote !== undefined) {
- feeCurrencyCode = quote;
}
fee = {
'cost': feeCost,
@@ -38823,9 +48210,6 @@ module.exports = class coinbasepro extends Exchange {
'rate': undefined,
};
}
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
const id = this.safeString (order, 'id');
const type = this.safeString (order, 'type');
const side = this.safeString (order, 'side');
@@ -38837,10 +48221,12 @@ module.exports = class coinbasepro extends Exchange {
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'status': status,
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -39018,30 +48404,49 @@ module.exports = class coinbasepro extends Exchange {
let currency = undefined;
let id = this.safeString (params, 'id'); // account id
if (id === undefined) {
- if (code === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchTransactions() requires a currency code argument if no account id specified in params');
+ if (code !== undefined) {
+ currency = this.currency (code);
+ const accountsByCurrencyCode = this.indexBy (this.accounts, 'currency');
+ const account = this.safeValue (accountsByCurrencyCode, code);
+ if (account === undefined) {
+ throw new ExchangeError (this.id + ' fetchTransactions() could not find account id for ' + code);
+ }
+ id = account['id'];
}
- currency = this.currency (code);
- const accountsByCurrencyCode = this.indexBy (this.accounts, 'currency');
- const account = this.safeValue (accountsByCurrencyCode, code);
- if (account === undefined) {
- throw new ExchangeError (this.id + ' fetchTransactions() could not find account id for ' + code);
- }
- id = account['id'];
}
- const request = {
- 'id': id,
- };
+ const request = {};
+ if (id !== undefined) {
+ request['id'] = id;
+ }
if (limit !== undefined) {
request['limit'] = limit;
}
- const response = await this.privateGetAccountsIdTransfers (this.extend (request, params));
- for (let i = 0; i < response.length; i++) {
- response[i]['currency'] = code;
+ let response = undefined;
+ if (id === undefined) {
+ response = await this.privateGetTransfers (this.extend (request, params));
+ for (let i = 0; i < response.length; i++) {
+ const account_id = this.safeString (response[i], 'account_id');
+ const account = this.safeValue (this.accountsById, account_id);
+ const code = this.safeString (account, 'currency');
+ response[i]['currency'] = code;
+ }
+ } else {
+ response = await this.privateGetAccountsIdTransfers (this.extend (request, params));
+ for (let i = 0; i < response.length; i++) {
+ response[i]['currency'] = code;
+ }
}
return this.parseTransactions (response, currency, since, limit);
}
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return this.fetchTransactions (code, since, limit, this.extend (params, { 'type': 'deposit' }));
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return this.fetchTransactions (code, since, limit, this.extend (params, { 'type': 'withdraw' }));
+ }
+
parseTransactionStatus (transaction) {
const canceled = this.safeValue (transaction, 'canceled_at');
if (canceled) {
@@ -39066,16 +48471,23 @@ module.exports = class coinbasepro extends Exchange {
const updated = this.parse8601 (this.safeString (transaction, 'processed_at'));
const currencyId = this.safeString (transaction, 'currency');
const code = this.safeCurrencyCode (currencyId, currency);
- const fee = undefined;
const status = this.parseTransactionStatus (transaction);
const amount = this.safeFloat (transaction, 'amount');
let type = this.safeString (transaction, 'type');
let address = this.safeString (details, 'crypto_address');
const tag = this.safeString (details, 'destination_tag');
address = this.safeString (transaction, 'crypto_address', address);
+ let fee = undefined;
if (type === 'withdraw') {
type = 'withdrawal';
address = this.safeString (details, 'sent_to_address', address);
+ const feeCost = this.safeFloat (details, 'fee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'code': code,
+ };
+ }
}
return {
'info': transaction,
@@ -39118,7 +48530,7 @@ module.exports = class coinbasepro extends Exchange {
const signature = this.hmac (this.encode (what), secret, 'sha256', 'base64');
headers = {
'CB-ACCESS-KEY': this.apiKey,
- 'CB-ACCESS-SIGN': this.decode (signature),
+ 'CB-ACCESS-SIGN': signature,
'CB-ACCESS-TIMESTAMP': nonce,
'CB-ACCESS-PASSPHRASE': this.password,
'Content-Type': 'application/json',
@@ -39127,35 +48539,6 @@ module.exports = class coinbasepro extends Exchange {
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
- async fetchDepositAddress (code, params = {}) {
- await this.loadMarkets ();
- const currency = this.currency (code);
- let accounts = this.safeValue (this.options, 'coinbaseAccounts');
- if (accounts === undefined) {
- accounts = await this.privateGetCoinbaseAccounts ();
- this.options['coinbaseAccounts'] = accounts; // cache it
- this.options['coinbaseAccountsByCurrencyId'] = this.indexBy (accounts, 'currency');
- }
- const currencyId = currency['id'];
- const account = this.safeValue (this.options['coinbaseAccountsByCurrencyId'], currencyId);
- if (account === undefined) {
- // eslint-disable-next-line quotes
- throw new InvalidAddress (this.id + " fetchDepositAddress() could not find currency code " + code + " with id = " + currencyId + " in this.options['coinbaseAccountsByCurrencyId']");
- }
- const request = {
- 'id': account['id'],
- };
- const response = await this.privateGetCoinbaseAccountsIdAddresses (this.extend (request, params));
- const address = this.safeString (response, 'address');
- const tag = this.safeString (response, 'destination_tag');
- return {
- 'currency': code,
- 'address': this.checkAddress (address),
- 'tag': tag,
- 'info': response,
- };
- }
-
async createDepositAddress (code, params = {}) {
await this.loadMarkets ();
const currency = this.currency (code);
@@ -39209,7 +48592,7 @@ module.exports = class coinbasepro extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],63:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],63:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -39227,12 +48610,18 @@ module.exports = class coincheck extends Exchange {
'countries': [ 'JP', 'ID' ],
'rateLimit': 1500,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchMyTrades': true,
+ 'fetchOrderBook': true,
+ 'fetchOpenOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27766464-3b5c3c74-5ed9-11e7-840e-31b32968e1da.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87182088-1d6d6380-c2ec-11ea-9c64-8ab9f9b289f5.jpg',
'api': 'https://coincheck.com/api',
'www': 'https://coincheck.com',
'doc': 'https://coincheck.com/documents/exchange/api',
@@ -39390,18 +48779,7 @@ module.exports = class coincheck extends Exchange {
}
const status = undefined;
const marketId = this.safeString (order, 'pair');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
return {
'id': id,
'clientOrderId': undefined,
@@ -39413,9 +48791,11 @@ module.exports = class coincheck extends Exchange {
'filled': filled,
'side': side,
'type': undefined,
+ 'timeInForce': undefined,
'status': status,
'symbol': symbol,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'fee': undefined,
'info': order,
@@ -39644,7 +49024,7 @@ module.exports = class coincheck extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],64:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],64:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -39661,11 +49041,18 @@ module.exports = class coinegg extends Exchange {
'name': 'CoinEgg',
'countries': [ 'CN', 'UK' ],
'has': {
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': 'emulated',
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchMyTrades': false,
+ 'fetchOpenOrders': 'emulated',
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
'fetchTickers': false,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/36770310-adfa764e-1c5a-11e8-8e09-449daac3d2fb.jpg',
@@ -40006,8 +49393,10 @@ module.exports = class coinegg extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': undefined,
'amount': amount,
'filled': filled,
@@ -40040,7 +49429,6 @@ module.exports = class coinegg extends Exchange {
'type': side,
'info': response,
}, market);
- this.orders[id] = order;
return order;
}
@@ -40064,7 +49452,8 @@ module.exports = class coinegg extends Exchange {
'quote': market['quoteId'],
};
const response = await this.privatePostTradeViewRegionQuote (this.extend (request, params));
- return this.parseOrder (response['data'], market);
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -40078,7 +49467,8 @@ module.exports = class coinegg extends Exchange {
request['since'] = since / 1000;
}
const response = await this.privatePostTradeListRegionQuote (this.extend (request, params));
- return this.parseOrders (response['data'], market, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOrders (data, market, since, limit);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -40151,7 +49541,7 @@ module.exports = class coinegg extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],65:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],65:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -40170,15 +49560,22 @@ module.exports = class coinex extends Exchange {
'countries': [ 'CN' ],
'rateLimit': 1000,
'has': {
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchMyTrades': true,
- 'withdraw': true,
'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1min',
@@ -40196,7 +49593,7 @@ module.exports = class coinex extends Exchange {
'1w': '1week',
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/38046312-0b450aac-32c8-11e8-99ab-bc6b136b6cc7.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87182089-1e05fa00-c2ec-11ea-8da9-cc73b45abbbc.jpg',
'api': 'https://api.coinex.com',
'www': 'https://www.coinex.com',
'doc': 'https://github.com/coinexcom/coinex_exchange_api/wiki',
@@ -40412,19 +49809,16 @@ module.exports = class coinex extends Exchange {
const result = {};
for (let i = 0; i < marketIds.length; i++) {
const marketId = marketIds[i];
- let symbol = marketId;
- let market = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
- const ticker = {
+ const market = this.safeMarket (marketId);
+ const symbol = market['symbol'];
+ const ticker = this.parseTicker ({
'date': timestamp,
'ticker': tickers[marketId],
- };
- result[symbol] = this.parseTicker (ticker, market);
+ }, market);
+ ticker['symbol'] = symbol;
+ result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = 20, params = {}) {
@@ -40452,11 +49846,7 @@ module.exports = class coinex extends Exchange {
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'amount');
const marketId = this.safeString (trade, 'market');
- market = this.safeValue (this.markets_by_id, marketId, market);
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
let cost = this.safeFloat (trade, 'deal_money');
if (!cost) {
cost = parseFloat (this.costToPrecision (symbol, price * amount));
@@ -40500,14 +49890,26 @@ module.exports = class coinex extends Exchange {
return this.parseTrades (response['data'], market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591484400,
+ // "0.02505349",
+ // "0.02506988",
+ // "0.02507000",
+ // "0.02505304",
+ // "343.19716223",
+ // "8.6021323866383196",
+ // "ETHBTC"
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[5]),
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -40518,8 +49920,23 @@ module.exports = class coinex extends Exchange {
'market': market['id'],
'type': this.timeframes[timeframe],
};
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
const response = await this.publicGetMarketKline (this.extend (request, params));
- return this.parseOHLCVs (response['data'], market, timeframe, since, limit);
+ //
+ // {
+ // "code": 0,
+ // "data": [
+ // [1591484400, "0.02505349", "0.02506988", "0.02507000", "0.02505304", "343.19716223", "8.6021323866383196", "ETHBTC"],
+ // [1591484700, "0.02506990", "0.02508109", "0.02508109", "0.02506979", "91.59841581", "2.2972047780447000", "ETHBTC"],
+ // [1591485000, "0.02508106", "0.02507996", "0.02508106", "0.02507500", "65.15307697", "1.6340597822306000", "ETHBTC"],
+ // ],
+ // "message": "OK"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async fetchBalance (params = {}) {
@@ -40603,7 +50020,7 @@ module.exports = class coinex extends Exchange {
const average = this.safeFloat (order, 'avg_price');
let symbol = undefined;
const marketId = this.safeString (order, 'market');
- market = this.safeValue (this.markets_by_id, marketId);
+ market = this.safeMarket (marketId, market);
const feeCurrencyId = this.safeString (order, 'fee_asset');
let feeCurrency = this.safeCurrencyCode (feeCurrencyId);
if (market !== undefined) {
@@ -40625,8 +50042,10 @@ module.exports = class coinex extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -40669,10 +50088,8 @@ module.exports = class coinex extends Exchange {
request['price'] = this.priceToPrecision (symbol, price);
}
const response = await this[method] (this.extend (request, params));
- const order = this.parseOrder (response['data'], market);
- const id = order['id'];
- this.orders[id] = order;
- return order;
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -40683,7 +50100,8 @@ module.exports = class coinex extends Exchange {
'market': market['id'],
};
const response = await this.privateDeleteOrderPending (this.extend (request, params));
- return this.parseOrder (response['data'], market);
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async fetchOrder (id, symbol = undefined, params = {}) {
@@ -40723,7 +50141,8 @@ module.exports = class coinex extends Exchange {
// "message": "Ok"
// }
//
- return this.parseOrder (response['data'], market);
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async fetchOrdersByStatus (status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -40742,7 +50161,9 @@ module.exports = class coinex extends Exchange {
}
const method = 'privateGetOrder' + this.capitalize (status);
const response = await this[method] (this.extend (request, params));
- return this.parseOrders (response['data']['data'], market, since, limit);
+ const data = this.safeValue (response, 'data');
+ const orders = this.safeValue (data, 'data', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -40768,7 +50189,9 @@ module.exports = class coinex extends Exchange {
request['market'] = market['id'];
}
const response = await this.privateGetOrderUserDeals (this.extend (request, params));
- return this.parseTrades (response['data']['data'], market, since, limit);
+ const data = this.safeValue (response, 'data');
+ const trades = this.safeValue (data, 'data', []);
+ return this.parseTrades (trades, market, since, limit);
}
async withdraw (code, amount, address, tag = undefined, params = {}) {
@@ -40782,7 +50205,7 @@ module.exports = class coinex extends Exchange {
'coin_type': currency['id'],
'coin_address': address, // must be authorized, inter-user transfer by a registered mobile phone number or an email address is supported
'actual_amount': parseFloat (amount), // the actual amount without fees, https://www.coinex.com/fees
- 'transfer_method': '1', // '1' = normal onchain transfer, '2' = internal local transfer from one user to another
+ 'transfer_method': 'onchain', // onchain, local
};
const response = await this.privatePostBalanceCoinWithdraw (this.extend (request, params));
//
@@ -40922,48 +50345,46 @@ module.exports = class coinex extends Exchange {
//
// {
// "code": 0,
- // "data": [
- // {
- // "actual_amount": "1.00000000",
- // "amount": "1.00000000",
- // "coin_address": "1KAv3pazbTk2JnQ5xTo6fpKK7p1it2RzD4",
- // "coin_type": "BCH",
- // "coin_withdraw_id": 206,
- // "confirmations": 0,
- // "create_time": 1524228297,
- // "status": "audit",
- // "tx_fee": "0",
- // "tx_id": ""
- // },
- // {
- // "actual_amount": "0.10000000",
- // "amount": "0.10000000",
- // "coin_address": "15sr1VdyXQ6sVLqeJUJ1uPzLpmQtgUeBSB",
- // "coin_type": "BCH",
- // "coin_withdraw_id": 203,
- // "confirmations": 11,
- // "create_time": 1515806440,
- // "status": "finish",
- // "tx_fee": "0",
- // "tx_id": "896371d0e23d64d1cac65a0b7c9e9093d835affb572fec89dd4547277fbdd2f6"
- // },
- // {
- // "actual_amount": "0.00100000",
- // "amount": "0.00100000",
- // "coin_address": "1GVVx5UBddLKrckTprNi4VhHSymeQ8tsLF",
- // "coin_type": "BCH",
- // "coin_withdraw_id": 27,
- // "confirmations": 0,
- // "create_time": 1513933541,
- // "status": "cancel",
- // "tx_fee": "0",
- // "tx_id": ""
- // }
- // ],
- // "message": "Ok"
+ // "data": {
+ // "has_next": true,
+ // "curr_page": 1,
+ // "count": 10,
+ // "data": [
+ // {
+ // "coin_withdraw_id": 203,
+ // "create_time": 1513933541,
+ // "actual_amount": "0.00100000",
+ // "actual_amount_display": "***",
+ // "amount": "0.00100000",
+ // "amount_display": "******",
+ // "coin_address": "1GVVx5UBddLKrckTprNi4VhHSymeQ8tsLF",
+ // "app_coin_address_display": "**********",
+ // "coin_address_display": "****************",
+ // "add_explorer": "https://explorer.viawallet.com/btc/address/1GVVx5UBddLKrckTprNi4VhHSymeQ8tsLF",
+ // "coin_type": "BTC",
+ // "confirmations": 6,
+ // "explorer": "https://explorer.viawallet.com/btc/tx/1GVVx5UBddLKrckTprNi4VhHSymeQ8tsLF",
+ // "fee": "0",
+ // "remark": "",
+ // "smart_contract_name": "BTC",
+ // "status": "finish",
+ // "status_display": "finish",
+ // "transfer_method": "onchain",
+ // "tx_fee": "0",
+ // "tx_id": "896371d0e23d64d1cac65a0b7c9e9093d835affb572fec89dd4547277fbdd2f6"
+ // }, /* many more data points */
+ // ],
+ // "total": ***,
+ // "total_page":***
+ // },
+ // "message": "Success"
// }
//
- return this.parseTransactions (response['data'], currency, since, limit);
+ let data = this.safeValue (response, 'data');
+ if (!Array.isArray (data)) {
+ data = this.safeValue (data, 'data', []);
+ }
+ return this.parseTransactions (data, currency, since, limit);
}
async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
@@ -41006,7 +50427,11 @@ module.exports = class coinex extends Exchange {
// "message": "Ok"
// }
//
- return this.parseTransactions (response['data'], currency, since, limit);
+ let data = this.safeValue (response, 'data');
+ if (!Array.isArray (data)) {
+ data = this.safeValue (data, 'data', []);
+ }
+ return this.parseTransactions (data, currency, since, limit);
}
nonce () {
@@ -41066,7 +50491,7 @@ module.exports = class coinex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],66:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],66:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -41085,9 +50510,17 @@ module.exports = class coinfalcon extends Exchange {
'rateLimit': 1000,
'version': 'v1',
'has': {
- 'fetchTickers': true,
- 'fetchOpenOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/41822275-ed982188-77f5-11e8-92bb-496bcd14ca52.jpg',
@@ -41178,14 +50611,8 @@ module.exports = class coinfalcon extends Exchange {
}
parseTicker (ticker, market = undefined) {
- if (market === undefined) {
- const marketId = this.safeString (ticker, 'name');
- market = this.safeValue (this.markets_by_id, marketId, market);
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (ticker, 'name');
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.milliseconds ();
const last = parseFloat (ticker['last_price']);
return {
@@ -41228,7 +50655,7 @@ module.exports = class coinfalcon extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -41238,7 +50665,8 @@ module.exports = class coinfalcon extends Exchange {
'level': '3',
};
const response = await this.publicGetMarketsMarketOrders (this.extend (request, params));
- return this.parseOrderBook (response['data'], undefined, 'bids', 'asks', 'price', 'size');
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrderBook (data, undefined, 'bids', 'asks', 'price', 'size');
}
parseTrade (trade, market = undefined) {
@@ -41297,7 +50725,8 @@ module.exports = class coinfalcon extends Exchange {
request['limit'] = limit;
}
const response = await this.privateGetUserTrades (this.extend (request, params));
- return this.parseTrades (response['data'], market, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
}
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
@@ -41310,7 +50739,8 @@ module.exports = class coinfalcon extends Exchange {
request['since'] = this.iso8601 (since);
}
const response = await this.publicGetMarketsMarketTrades (this.extend (request, params));
- return this.parseTrades (response['data'], market, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
}
async fetchBalance (params = {}) {
@@ -41361,16 +50791,8 @@ module.exports = class coinfalcon extends Exchange {
// "created_at":"2018-01-12T21:14:06.747828Z"
// }
//
- if (market === undefined) {
- const marketId = this.safeString (order, 'market');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const price = this.safeFloat (order, 'price');
const amount = this.safeFloat (order, 'size');
@@ -41379,10 +50801,10 @@ module.exports = class coinfalcon extends Exchange {
let cost = undefined;
if (amount !== undefined) {
if (filled !== undefined) {
- remaining = parseFloat (this.amountToPrecision (symbol, amount - filled));
+ remaining = Math.max (0, amount - filled);
}
if (price !== undefined) {
- cost = parseFloat (this.priceToPrecision (symbol, filled * price));
+ cost = filled * price;
}
}
const status = this.parseOrderStatus (this.safeString (order, 'status'));
@@ -41400,8 +50822,10 @@ module.exports = class coinfalcon extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -41429,10 +50853,8 @@ module.exports = class coinfalcon extends Exchange {
}
request['operation_type'] = type + '_order';
const response = await this.privatePostUserOrders (this.extend (request, params));
- const order = this.parseOrder (response['data'], market);
- const id = order['id'];
- this.orders[id] = order;
- return order;
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -41442,7 +50864,8 @@ module.exports = class coinfalcon extends Exchange {
};
const response = await this.privateDeleteUserOrdersId (this.extend (request, params));
const market = this.market (symbol);
- return this.parseOrder (response['data'], market);
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data, market);
}
async fetchOrder (id, symbol = undefined, params = {}) {
@@ -41451,21 +50874,26 @@ module.exports = class coinfalcon extends Exchange {
'id': id,
};
const response = await this.privateGetUserOrdersId (this.extend (request, params));
- return this.parseOrder (response['data']);
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
+ let market = undefined;
if (symbol !== undefined) {
- request['market'] = this.marketId (symbol);
+ market = this.market (symbol);
+ request['market'] = market['id'];
}
if (since !== undefined) {
- request['since_time'] = this.iso8601 (this.milliseconds ());
+ request['since_time'] = this.iso8601 (since);
}
// TODO: test status=all if it works for closed orders too
const response = await this.privateGetUserOrders (this.extend (request, params));
- return this.parseOrders (response['data']);
+ const data = this.safeValue (response, 'data', []);
+ const orders = this.filterByArray (data, 'status', [ 'pending', 'open', 'partially_filled' ], false);
+ return this.parseOrders (orders, market, since, limit);
}
nonce () {
@@ -41517,7 +50945,7 @@ module.exports = class coinfalcon extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],67:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],67:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -41535,11 +50963,18 @@ module.exports = class coinfloor extends Exchange {
'rateLimit': 1000,
'countries': [ 'UK' ],
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchLedger': true,
'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/28246081-623fc164-6a1c-11e7-913f-bac0d5576c90.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87153925-ef265e80-c2c0-11ea-91b5-020c804b90e0.jpg',
'api': 'https://webapi.coinfloor.co.uk/bist',
'www': 'https://www.coinfloor.co.uk',
'doc': [
@@ -41919,7 +51354,27 @@ module.exports = class coinfloor extends Exchange {
request['price'] = price;
request['amount'] = amount;
}
- return await this[method] (this.extend (request, params));
+ //
+ // {
+ // "id":31950584,
+ // "datetime":"2020-05-21 08:38:18",
+ // "type":1,
+ // "price":"9100",
+ // "amount":"0.0026"
+ // }
+ //
+ const response = await this[method] (this.extend (request, params));
+ const timestamp = this.parse8601 (this.safeString (response, 'datetime'));
+ return {
+ 'id': this.safeString (response, 'id'),
+ 'clientOrderId': undefined,
+ 'datetime': this.iso8601 (timestamp),
+ 'timestamp': timestamp,
+ 'type': type,
+ 'price': this.safeFloat (response, 'price'),
+ 'remaining': this.safeFloat (response, 'amount'),
+ 'info': response,
+ };
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -41972,11 +51427,13 @@ module.exports = class coinfloor extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
- 'amount': amount,
+ 'stopPrice': undefined,
+ 'amount': undefined,
'filled': undefined,
- 'remaining': undefined,
+ 'remaining': amount,
'cost': cost,
'fee': undefined,
'average': undefined,
@@ -42030,7 +51487,7 @@ module.exports = class coinfloor extends Exchange {
const nonce = this.nonce ();
body = this.urlencode (this.extend ({ 'nonce': nonce }, query));
const auth = this.uid + '/' + this.apiKey + ':' + this.password;
- const signature = this.decode (this.stringToBase64 (this.encode (auth)));
+ const signature = this.decode (this.stringToBase64 (auth));
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + signature,
@@ -42040,7 +51497,7 @@ module.exports = class coinfloor extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],68:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],68:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -42058,8 +51515,15 @@ module.exports = class coingi extends Exchange {
'rateLimit': 1000,
'countries': [ 'PA', 'BG', 'CN', 'US' ], // Panama, Bulgaria, China, US
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'referral': 'https://www.coingi.com/?r=XTPPMC',
@@ -42269,7 +51733,7 @@ module.exports = class coingi extends Exchange {
}
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -42293,13 +51757,7 @@ module.exports = class coingi extends Exchange {
const timestamp = this.safeInteger (trade, 'timestamp');
const id = this.safeString (trade, 'id');
const marketId = this.safeString (trade, 'currencyPair');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
return {
'id': id,
'info': trade,
@@ -42389,7 +51847,7 @@ module.exports = class coingi extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],69:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],69:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -42408,23 +51866,25 @@ module.exports = class coinmarketcap extends Exchange {
'version': 'v1',
'countries': [ 'US' ],
'has': {
- 'CORS': true,
- 'privateAPI': false,
- 'createOrder': false,
- 'createMarketOrder': false,
- 'createLimitOrder': false,
'cancelOrder': false,
+ 'CORS': true,
+ 'createLimitOrder': false,
+ 'createMarketOrder': false,
+ 'createOrder': false,
'editOrder': false,
+ 'privateAPI': false,
'fetchBalance': false,
- 'fetchOrderBook': false,
- 'fetchL2OrderBook': false,
- 'fetchOHLCV': false,
- 'fetchTrades': false,
- 'fetchTickers': true,
'fetchCurrencies': true,
+ 'fetchL2OrderBook': false,
+ 'fetchMarkets': true,
+ 'fetchOHLCV': false,
+ 'fetchOrderBook': false,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': false,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/28244244-9be6312a-69ed-11e7-99c1-7c1797275265.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87182086-1cd4cd00-c2ec-11ea-9ec4-d0cf2a2abf62.jpg',
'api': {
'public': 'https://api.coinmarketcap.com',
'files': 'https://files.coinmarketcap.com',
@@ -42488,24 +51948,29 @@ module.exports = class coinmarketcap extends Exchange {
'ACChain': 'ACChain',
'AdCoin': 'AdCoin',
'BatCoin': 'BatCoin',
+ 'BigONE Token': 'BigONE Token', // conflict with Harmony (ONE)
'Bitgem': 'Bitgem',
'BlazeCoin': 'BlazeCoin',
'BlockCAT': 'BlockCAT',
'Blocktrade Token': 'Blocktrade Token',
+ 'BOX Token': 'BOX Token', // conflict with BOX (ContentBox)
'Catcoin': 'Catcoin',
'CanYaCoin': 'CanYaCoin', // conflict with CAN (Content and AD Network)
+ 'CryptoBossCoin': 'CryptoBossCoin', // conflict with CBC (CashBet Coin)
'Comet': 'Comet', // conflict with CMT (CyberMiles)
'CPChain': 'CPChain',
'CrowdCoin': 'CrowdCoin', // conflict with CRC CryCash
'Cryptaur': 'Cryptaur', // conflict with CPT = Contents Protocol https://github.com/ccxt/ccxt/issues/4920 and https://github.com/ccxt/ccxt/issues/6081
'Cubits': 'Cubits', // conflict with QBT (Qbao)
'DAO.Casino': 'DAO.Casino', // conflict with BET (BetaCoin)
+ 'DefiBox': 'DefiBox', // conflict with BOX (ContentBox)
'E-Dinar Coin': 'E-Dinar Coin', // conflict with EDR Endor Protocol and EDRCoin
'EDRcoin': 'EDRcoin', // conflict with EDR Endor Protocol and E-Dinar Coin
'ENTCash': 'ENTCash', // conflict with ENT (Eternity)
'FairCoin': 'FairCoin', // conflict with FAIR (FairGame) https://github.com/ccxt/ccxt/pull/5865
'Fabric Token': 'Fabric Token',
// 'GET Protocol': 'GET Protocol',
+ 'GHOSTPRISM': 'GHOSTPRISM', // conflict with GHOST
'Global Tour Coin': 'Global Tour Coin', // conflict with GTC (Game.com)
'GuccioneCoin': 'GuccioneCoin', // conflict with GCC (Global Cryptocurrency)
'HarmonyCoin': 'HarmonyCoin', // conflict with HMC (Hi Mutual Society)
@@ -42515,14 +51980,18 @@ module.exports = class coinmarketcap extends Exchange {
'Huncoin': 'Huncoin', // conflict with HNC (Helleniccoin)
'iCoin': 'iCoin',
'Infinity Economics': 'Infinity Economics', // conflict with XIN (Mixin)
+ 'IQ.cash': 'IQ.cash', // conflict with IQ (Everipedia)
'KingN Coin': 'KingN Coin', // conflict with KNC (Kyber Network)
'LiteBitcoin': 'LiteBitcoin', // conflict with LBTC (LightningBitcoin)
'Maggie': 'Maggie',
+ 'Menlo One': 'Menlo One', // conflict with Harmony (ONE)
+ 'Mobilian Coin': 'Mobilian Coin', // conflict with Membrana (MBN)
'Monarch': 'Monarch', // conflict with MyToken (MT)
'MTC Mesh Network': 'MTC Mesh Network', // conflict with MTC Docademic doc.com Token https://github.com/ccxt/ccxt/issues/6081 https://github.com/ccxt/ccxt/issues/3025
'IOTA': 'IOTA', // a special case, most exchanges list it as IOTA, therefore we change just the Coinmarketcap instead of changing them all
'NetCoin': 'NetCoin',
'PCHAIN': 'PCHAIN', // conflict with PAI (Project Pai)
+ 'Penta': 'Penta', // conflict with PNT (pNetwork)
'Plair': 'Plair', // conflict with PLA (PLANET)
'PlayChip': 'PlayChip', // conflict with PLA (PLANET)
'Polcoin': 'Polcoin',
@@ -42531,9 +52000,11 @@ module.exports = class coinmarketcap extends Exchange {
// https://github.com/ccxt/ccxt/issues/6081
// https://github.com/ccxt/ccxt/issues/3365
// https://github.com/ccxt/ccxt/issues/2873
+ 'TerraCredit': 'TerraCredit', // conflict with CREDIT (PROXI)
'Themis': 'Themis', // conflict with GET (Guaranteed Entrance Token, GET Protocol)
- 'Menlo One': 'Menlo One', // conflict with Harmony (ONE)
- 'BigONE Token': 'BigONE Token', // conflict with Harmony (ONE)
+ 'UNI COIN': 'UNI COIN', // conflict with UNI (Uniswap)
+ 'UNICORN Token': 'UNICORN Token', // conflict with UNI (Uniswap)
+ 'Universe': 'Universe', // conflict with UNI (Uniswap)
};
return this.safeValue (currencies, name, base);
}
@@ -42723,7 +52194,7 @@ module.exports = class coinmarketcap extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],70:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],70:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -42741,18 +52212,22 @@ module.exports = class coinmate extends Exchange {
'countries': [ 'GB', 'CZ', 'EU' ], // UK, Czech Republic
'rateLimit': 1000,
'has': {
- 'CORS': true,
- 'fetchBalance': true,
- 'fetchOrders': true,
- 'fetchOrder': true,
- 'fetchMyTrades': true,
- 'fetchTransactions': true,
- 'fetchOpenOrders': true,
- 'createOrder': true,
'cancelOrder': true,
+ 'CORS': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27811229-c1efb510-606c-11e7-9a36-84ba2ce412d8.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87460806-1c9f3f00-c616-11ea-8c46-a77018a8f3f4.jpg',
'api': 'https://coinmate.io/api',
'www': 'https://coinmate.io',
'fees': 'https://coinmate.io/fees',
@@ -43119,7 +52594,7 @@ module.exports = class coinmate extends Exchange {
'status': status,
'fee': {
'cost': fee,
- 'currency': currency,
+ 'currency': code,
},
'info': item,
};
@@ -43173,25 +52648,8 @@ module.exports = class coinmate extends Exchange {
// "tradeType":"BUY"
// }
//
- let symbol = undefined;
const marketId = this.safeString (trade, 'currencyPair');
- let quote = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id[marketId]) {
- market = this.markets_by_id[marketId];
- quote = market['quote'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ market = this.safeMarket (marketId, market, '_');
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'amount');
let cost = undefined;
@@ -43210,7 +52668,7 @@ module.exports = class coinmate extends Exchange {
if (feeCost !== undefined) {
fee = {
'cost': feeCost,
- 'currency': quote,
+ 'currency': market['quote'],
};
}
let takerOrMaker = this.safeString (trade, 'feeType');
@@ -43220,7 +52678,7 @@ module.exports = class coinmate extends Exchange {
'info': trade,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': type,
'side': side,
'order': orderId,
@@ -43348,14 +52806,17 @@ module.exports = class coinmate extends Exchange {
const timestamp = this.safeInteger (order, 'timestamp');
const side = this.safeStringLower (order, 'type');
const price = this.safeFloat (order, 'price');
- const amount = this.safeFloat2 (order, 'originalAmount', 'amount');
- const remaining = this.safeFloat (order, 'remainingAmount', amount);
+ const amount = this.safeFloat (order, 'originalAmount');
+ let remaining = this.safeFloat (order, 'remainingAmount');
+ if (remaining === undefined) {
+ remaining = this.safeFloat (order, 'amount');
+ }
let status = this.parseOrderStatus (this.safeString (order, 'status'));
const type = this.parseOrderType (this.safeString (order, 'orderTradeType'));
let filled = undefined;
let cost = undefined;
if ((amount !== undefined) && (remaining !== undefined)) {
- filled = Math.min (amount - remaining, 0);
+ filled = Math.max (amount - remaining, 0);
if (remaining === 0) {
status = 'closed';
}
@@ -43364,22 +52825,10 @@ module.exports = class coinmate extends Exchange {
}
}
const average = this.safeFloat (order, 'avgPrice');
- let symbol = undefined;
const marketId = this.safeString (order, 'currencyPair');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const clientOrderId = this.safeString (order, 'clientOrderId');
+ const stopPrice = this.safeFloat (order, 'stopPrice');
return {
'id': id,
'clientOrderId': clientOrderId,
@@ -43388,8 +52837,10 @@ module.exports = class coinmate extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -43504,13 +52955,13 @@ module.exports = class coinmate extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],71:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],71:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { BadSymbol, BadRequest, ExchangeError, ArgumentsRequired, InvalidOrder, OrderNotFound, OnMaintenance } = require ('./base/errors');
+const { BadSymbol, BadRequest, ExchangeError, ArgumentsRequired, OrderNotFound, OnMaintenance } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -43520,13 +52971,27 @@ module.exports = class coinone extends Exchange {
'id': 'coinone',
'name': 'CoinOne',
'countries': [ 'KR' ], // Korea
+ // 'enableRateLimit': false,
'rateLimit': 667,
'version': 'v2',
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createMarketOrder': false,
- 'fetchTickers': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': false,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ // https://github.com/ccxt/ccxt/pull/7067
+ // the endpoint that should return closed orders actually returns trades
+ 'fetchClosedOrders': false,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/38003300-adc12fba-323f-11e8-8525-725f53c4a659.jpg',
@@ -43568,67 +53033,58 @@ module.exports = class coinone extends Exchange {
],
},
},
- 'markets': {
- 'BCH/KRW': { 'id': 'bch', 'symbol': 'BCH/KRW', 'base': 'BCH', 'quote': 'KRW', 'baseId': 'bch', 'quoteId': 'krw' },
- 'BTC/KRW': { 'id': 'btc', 'symbol': 'BTC/KRW', 'base': 'BTC', 'quote': 'KRW', 'baseId': 'btc', 'quoteId': 'krw' },
- 'BTG/KRW': { 'id': 'btg', 'symbol': 'BTG/KRW', 'base': 'BTG', 'quote': 'KRW', 'baseId': 'btg', 'quoteId': 'krw' },
- 'ETC/KRW': { 'id': 'etc', 'symbol': 'ETC/KRW', 'base': 'ETC', 'quote': 'KRW', 'baseId': 'etc', 'quoteId': 'krw' },
- 'ETH/KRW': { 'id': 'eth', 'symbol': 'ETH/KRW', 'base': 'ETH', 'quote': 'KRW', 'baseId': 'eth', 'quoteId': 'krw' },
- 'IOTA/KRW': { 'id': 'iota', 'symbol': 'IOTA/KRW', 'base': 'IOTA', 'quote': 'KRW', 'baseId': 'iota', 'quoteId': 'krw' },
- 'LTC/KRW': { 'id': 'ltc', 'symbol': 'LTC/KRW', 'base': 'LTC', 'quote': 'KRW', 'baseId': 'ltc', 'quoteId': 'krw' },
- 'OMG/KRW': { 'id': 'omg', 'symbol': 'OMG/KRW', 'base': 'OMG', 'quote': 'KRW', 'baseId': 'omg', 'quoteId': 'krw' },
- 'QTUM/KRW': { 'id': 'qtum', 'symbol': 'QTUM/KRW', 'base': 'QTUM', 'quote': 'KRW', 'baseId': 'qtum', 'quoteId': 'krw' },
- 'XRP/KRW': { 'id': 'xrp', 'symbol': 'XRP/KRW', 'base': 'XRP', 'quote': 'KRW', 'baseId': 'xrp', 'quoteId': 'krw' },
- 'EOS/KRW': { 'id': 'eos', 'symbol': 'EOS/KRW', 'base': 'EOS', 'quote': 'KRW', 'baseId': 'eos', 'quoteId': 'krw' },
- 'DATA/KRW': { 'id': 'data', 'symbol': 'DATA/KRW', 'base': 'DATA', 'quote': 'KRW', 'baseId': 'data', 'quoteId': 'krw' },
- 'ZIL/KRW': { 'id': 'zil', 'symbol': 'ZIL/KRW', 'base': 'ZIL', 'quote': 'KRW', 'baseId': 'zil', 'quoteId': 'krw' },
- 'KNC/KRW': { 'id': 'knc', 'symbol': 'KNC/KRW', 'base': 'KNC', 'quote': 'KRW', 'baseId': 'knc', 'quoteId': 'krw' },
- 'ZRX/KRW': { 'id': 'zrx', 'symbol': 'ZRX/KRW', 'base': 'ZRX', 'quote': 'KRW', 'baseId': 'zrx', 'quoteId': 'krw' },
- 'LUNA/KRW': { 'id': 'luna', 'symbol': 'LUNA/KRW', 'base': 'LUNA', 'quote': 'KRW', 'baseId': 'luna', 'quoteId': 'krw' },
- 'ATOM/KRW': { 'id': 'atom', 'symbol': 'ATOM/KRW', 'base': 'ATOM', 'quote': 'KRW', 'baseId': 'atom', 'quoteId': 'krw' },
- 'VNT/KRW': { 'id': 'vnt', 'symbol': 'VNT/KRW', 'base': 'VNT', 'quote': 'KRW', 'baseId': 'vnt', 'quoteId': 'krw' },
- },
'fees': {
'trading': {
- 'tierBased': true,
+ 'tierBased': false,
'percentage': true,
- 'taker': 0.001,
- 'maker': 0.001,
- 'tiers': {
- 'taker': [
- [0, 0.001],
- [100000000, 0.0009],
- [1000000000, 0.0008],
- [5000000000, 0.0007],
- [10000000000, 0.0006],
- [20000000000, 0.0005],
- [30000000000, 0.0004],
- [40000000000, 0.0003],
- [50000000000, 0.0002],
- ],
- 'maker': [
- [0, 0.001],
- [100000000, 0.0008],
- [1000000000, 0.0006],
- [5000000000, 0.0004],
- [10000000000, 0.0002],
- [20000000000, 0],
- [30000000000, 0],
- [40000000000, 0],
- [50000000000, 0],
- ],
- },
+ 'taker': 0.002,
+ 'maker': 0.002,
},
},
+ 'precision': {
+ 'price': 4,
+ 'amount': 4,
+ 'cost': 8,
+ },
'exceptions': {
'405': OnMaintenance, // {"errorCode":"405","status":"maintenance","result":"error"}
- '104': OrderNotFound,
+ '104': OrderNotFound, // {"errorCode":"104","errorMsg":"Order id is not exist","result":"error"}
'108': BadSymbol, // {"errorCode":"108","errorMsg":"Unknown CryptoCurrency","result":"error"}
'107': BadRequest, // {"errorCode":"107","errorMsg":"Parameter error","result":"error"}
},
});
}
+ async fetchMarkets (params = {}) {
+ const request = {
+ 'currency': 'all',
+ };
+ const response = await this.publicGetTicker (request);
+ const result = [];
+ const quoteId = 'krw';
+ const quote = this.safeCurrencyCode (quoteId);
+ const baseIds = Object.keys (response);
+ for (let i = 0; i < baseIds.length; i++) {
+ const baseId = baseIds[i];
+ const ticker = this.safeValue (response, baseId, {});
+ const currency = this.safeValue (ticker, 'currency');
+ if (currency === undefined) {
+ continue;
+ }
+ const base = this.safeCurrencyCode (baseId);
+ result.push ({
+ 'id': baseId,
+ 'symbol': base + '/' + quote,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'active': true,
+ });
+ }
+ return result;
+ }
+
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.privatePostAccountBalance (params);
@@ -43659,7 +53115,8 @@ module.exports = class coinone extends Exchange {
'format': 'json',
};
const response = await this.publicGetOrderbook (this.extend (request, params));
- return this.parseOrderBook (response, undefined, 'bid', 'ask', 'price', 'qty');
+ const timestamp = this.safeTimestamp (response, 'timestamp');
+ return this.parseOrderBook (response, timestamp, 'bid', 'ask', 'price', 'qty');
}
async fetchTickers (symbols = undefined, params = {}) {
@@ -43671,6 +53128,7 @@ module.exports = class coinone extends Exchange {
const response = await this.publicGetTicker (this.extend (request, params));
const result = {};
const ids = Object.keys (response);
+ const timestamp = this.safeTimestamp (response, 'timestamp');
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
let symbol = id;
@@ -43680,9 +53138,10 @@ module.exports = class coinone extends Exchange {
symbol = market['symbol'];
const ticker = response[id];
result[symbol] = this.parseTicker (ticker, market);
+ result[symbol]['timestamp'] = timestamp;
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -43697,12 +53156,21 @@ module.exports = class coinone extends Exchange {
}
parseTicker (ticker, market = undefined) {
- const timestamp = this.milliseconds ();
+ const timestamp = this.safeTimestamp (ticker, 'timestamp');
+ const first = this.safeFloat (ticker, 'first');
const last = this.safeFloat (ticker, 'last');
+ let average = undefined;
+ if (first !== undefined && last !== undefined) {
+ average = this.sum (first, last) / 2;
+ }
const previousClose = this.safeFloat (ticker, 'yesterday_last');
let change = undefined;
+ let percentage = undefined;
if (last !== undefined && previousClose !== undefined) {
- change = previousClose - last;
+ change = last - previousClose;
+ if (previousClose !== 0) {
+ percentage = change / previousClose * 100;
+ }
}
const symbol = (market !== undefined) ? market['symbol'] : undefined;
return {
@@ -43716,13 +53184,13 @@ module.exports = class coinone extends Exchange {
'ask': undefined,
'askVolume': undefined,
'vwap': undefined,
- 'open': this.safeFloat (ticker, 'first'),
+ 'open': first,
'close': last,
'last': last,
'previousClose': previousClose,
'change': change,
- 'percentage': undefined,
- 'average': undefined,
+ 'percentage': percentage,
+ 'average': average,
'baseVolume': this.safeFloat (ticker, 'volume'),
'quoteVolume': undefined,
'info': ticker,
@@ -43730,14 +53198,44 @@ module.exports = class coinone extends Exchange {
}
parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // {
+ // "timestamp": "1416893212",
+ // "price": "420000.0",
+ // "qty": "0.1",
+ // "is_ask": "1"
+ // }
+ //
+ // fetchMyTrades (private)
+ //
+ // {
+ // "timestamp": "1416561032",
+ // "price": "419000.0",
+ // "type": "bid",
+ // "qty": "0.001",
+ // "feeRate": "-0.0015",
+ // "fee": "-0.0000015",
+ // "orderId": "E84A1AC2-8088-4FA0-B093-A3BCDB9B3C85"
+ // }
+ //
const timestamp = this.safeTimestamp (trade, 'timestamp');
const symbol = (market !== undefined) ? market['symbol'] : undefined;
const is_ask = this.safeString (trade, 'is_ask');
- let side = undefined;
- if (is_ask === '1') {
- side = 'sell';
- } else if (is_ask === '0') {
- side = 'buy';
+ let side = this.safeString (trade, 'type');
+ if (is_ask !== undefined) {
+ if (is_ask === '1') {
+ side = 'sell';
+ } else if (is_ask === '0') {
+ side = 'buy';
+ }
+ } else {
+ if (side === 'ask') {
+ side = 'sell';
+ } else if (side === 'bid') {
+ side = 'buy';
+ }
}
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'qty');
@@ -43747,12 +53245,29 @@ module.exports = class coinone extends Exchange {
cost = price * amount;
}
}
+ const orderId = this.safeString (trade, 'orderId');
+ let feeCost = this.safeFloat (trade, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ feeCost = Math.abs (feeCost);
+ let feeRate = this.safeFloat (trade, 'feeRate');
+ feeRate = Math.abs (feeRate);
+ let feeCurrencyCode = undefined;
+ if (market !== undefined) {
+ feeCurrencyCode = (side === 'sell') ? market['quote'] : market['base'];
+ }
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ 'rate': feeRate,
+ };
+ }
return {
- 'id': undefined,
+ 'id': this.safeString (trade, 'id'),
'info': trade,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'order': undefined,
+ 'order': orderId,
'symbol': symbol,
'type': undefined,
'side': side,
@@ -43760,7 +53275,7 @@ module.exports = class coinone extends Exchange {
'price': price,
'amount': amount,
'cost': cost,
- 'fee': undefined,
+ 'fee': fee,
};
}
@@ -43769,15 +53284,30 @@ module.exports = class coinone extends Exchange {
const market = this.market (symbol);
const request = {
'currency': market['id'],
- 'period': 'hour',
'format': 'json',
};
const response = await this.publicGetTrades (this.extend (request, params));
- return this.parseTrades (response['completeOrders'], market, since, limit);
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "timestamp": "1416895635",
+ // "currency": "btc",
+ // "completeOrders": [
+ // {
+ // "timestamp": "1416893212",
+ // "price": "420000.0",
+ // "qty": "0.1",
+ // "is_ask": "1"
+ // }
+ // ]
+ // }
+ //
+ const completeOrders = this.safeValue (response, 'completeOrders', []);
+ return this.parseTrades (completeOrders, market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- await this.loadMarkets ();
if (type !== 'limit') {
throw new ExchangeError (this.id + ' allows limit orders only');
}
@@ -43789,70 +53319,48 @@ module.exports = class coinone extends Exchange {
};
const method = 'privatePostOrder' + this.capitalize (type) + this.capitalize (side);
const response = await this[method] (this.extend (request, params));
- let id = this.safeString (response, 'orderId');
- if (id !== undefined) {
- id = id.toUpperCase ();
- }
- const timestamp = this.milliseconds ();
- const cost = price * amount;
- const order = {
- 'info': response,
- 'id': id,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'lastTradeTimestamp': undefined,
- 'symbol': symbol,
- 'type': type,
- 'side': side,
- 'price': price,
- 'cost': cost,
- 'average': undefined,
- 'amount': amount,
- 'filled': undefined,
- 'remaining': amount,
- 'status': 'open',
- 'fee': undefined,
- 'clientOrderId': undefined,
- 'trades': undefined,
- };
- this.orders[id] = order;
- return order;
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "orderId": "8a82c561-40b4-4cb3-9bc0-9ac9ffc1d63b"
+ // }
+ //
+ return this.parseOrder (response);
}
async fetchOrder (id, symbol = undefined, params = {}) {
- await this.loadMarkets ();
- let result = undefined;
- let market = undefined;
if (symbol === undefined) {
- if (id in this.orders) {
- market = this.market (this.orders[id]['symbol']);
- } else {
- throw new ArgumentsRequired (this.id + ' fetchOrder() requires a symbol argument for order ids missing in the .orders cache (the order was created with a different instance of this class or within a different run of this code).');
- }
- } else {
- market = this.market (symbol);
+ throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
}
- try {
- const request = {
- 'order_id': id,
- 'currency': market['id'],
- };
- const response = await this.privatePostOrderOrderInfo (this.extend (request, params));
- result = this.parseOrder (response);
- this.orders[id] = result;
- } catch (e) {
- if (e instanceof OrderNotFound) {
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- result = this.orders[id];
- } else {
- throw e;
- }
- } else {
- throw e;
- }
- }
- return result;
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'order_id': id,
+ 'currency': market['id'],
+ };
+ const response = await this.privatePostOrderOrderInfo (this.extend (request, params));
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "status": "live",
+ // "info": {
+ // "orderId": "32FF744B-D501-423A-8BA1-05BB6BE7814A",
+ // "currency": "BTC",
+ // "type": "bid",
+ // "price": "2922000.0",
+ // "qty": "115.4950",
+ // "remainQty": "45.4950",
+ // "feeRate": "0.0003",
+ // "fee": "0",
+ // "timestamp": "1499340941"
+ // }
+ // }
+ //
+ const info = this.safeValue (response, 'info', {});
+ info['status'] = this.safeString (info, 'status');
+ return this.parseOrder (info, market);
}
parseOrderStatus (status) {
@@ -43865,6 +53373,31 @@ module.exports = class coinone extends Exchange {
}
parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "orderId": "8a82c561-40b4-4cb3-9bc0-9ac9ffc1d63b"
+ // }
+ //
+ // fetchOrder
+ //
+ // {
+ // "status": "live", // injected in fetchOrder
+ // "orderId": "32FF744B-D501-423A-8BA1-05BB6BE7814A",
+ // "currency": "BTC",
+ // "type": "bid",
+ // "price": "2922000.0",
+ // "qty": "115.4950",
+ // "remainQty": "45.4950",
+ // "feeRate": "0.0003",
+ // "fee": "0",
+ // "timestamp": "1499340941"
+ // }
+ //
+ // fetchOpenOrders
//
// {
// "index": "0",
@@ -43876,44 +53409,62 @@ module.exports = class coinone extends Exchange {
// "feeRate": "-0.0015"
// }
//
- const info = this.safeValue (order, 'info');
- const id = this.safeStringUpper (info, 'orderId');
- const timestamp = this.safeTimestamp (info, 'timestamp');
- const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let cost = undefined;
- let side = this.safeString (info, 'type');
- if (side.indexOf ('ask') >= 0) {
+ const id = this.safeString (order, 'orderId');
+ const price = this.safeFloat (order, 'price');
+ const timestamp = this.safeTimestamp (order, 'timestamp');
+ let side = this.safeString (order, 'type');
+ if (side === 'ask') {
side = 'sell';
- } else {
+ } else if (side === 'bid') {
side = 'buy';
}
- const price = this.safeFloat (info, 'price');
- const amount = this.safeFloat (info, 'qty');
- const remaining = this.safeFloat (info, 'remainQty');
+ const remaining = this.safeFloat (order, 'remainQty');
let filled = undefined;
- if (amount !== undefined) {
- if (remaining !== undefined) {
- filled = amount - remaining;
- }
- if (price !== undefined) {
- cost = price * amount;
+ const amount = this.safeFloat (order, 'qty');
+ let status = this.safeString (order, 'status');
+ // https://github.com/ccxt/ccxt/pull/7067
+ if (status === 'live') {
+ if ((remaining !== undefined) && (amount !== undefined)) {
+ if (remaining < amount) {
+ status = 'canceled';
+ }
}
}
- const currency = this.safeString (info, 'currency');
- const fee = {
- 'currency': currency,
- 'cost': this.safeFloat (info, 'fee'),
- 'rate': this.safeFloat (info, 'feeRate'),
- };
+ if ((remaining !== undefined) && (amount !== undefined)) {
+ filled = Math.max (amount - remaining);
+ }
+ status = this.parseOrderStatus (status);
+ let cost = undefined;
+ if ((price !== undefined) && (filled !== undefined)) {
+ cost = price * filled;
+ }
let symbol = undefined;
- if (market === undefined) {
- const marketId = currency.toLowerCase ();
+ let base = undefined;
+ let quote = undefined;
+ const marketId = this.safeStringLower (order, 'currency');
+ if (marketId !== undefined) {
if (marketId in this.markets_by_id) {
market = this.markets_by_id[marketId];
+ } else {
+ base = this.safeCurrencyCode (marketId);
+ quote = 'KRW';
+ symbol = base + '/' + quote;
}
}
- if (market !== undefined) {
+ if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
+ base = market['base'];
+ quote = market['quote'];
+ }
+ let fee = undefined;
+ const feeCost = this.safeFloat (order, 'fee');
+ if (feeCost !== undefined) {
+ const feeCurrencyCode = (side === 'sell') ? quote : base;
+ fee = {
+ 'cost': feeCost,
+ 'rate': this.safeFloat (order, 'feeRate'),
+ 'currency': feeCurrencyCode,
+ };
}
return {
'info': order,
@@ -43924,60 +53475,116 @@ module.exports = class coinone extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
+ 'average': undefined,
'amount': amount,
'filled': filled,
- 'remaining': remaining,
+ 'remaining': amount,
'status': status,
'fee': fee,
- 'average': undefined,
'trades': undefined,
};
}
- async cancelOrder (id, symbol = undefined, params = {}) {
- await this.loadMarkets ();
- const order = this.safeValue (this.orders, id);
- let amount = undefined;
- let price = undefined;
- let side = undefined;
- if (order === undefined) {
- if (symbol === undefined) {
- // eslint-disable-next-line quotes
- throw new InvalidOrder (this.id + " cancelOrder could not find the order id " + id + " in orders cache. The order was probably created with a different instance of this class earlier. The `symbol` argument is missing. To cancel the order, pass a symbol argument and {'price': 12345, 'qty': 1.2345, 'is_ask': 0} in the params argument of cancelOrder.");
- }
- price = this.safeFloat (params, 'price');
- if (price === undefined) {
- // eslint-disable-next-line quotes
- throw new InvalidOrder (this.id + " cancelOrder could not find the order id " + id + " in orders cache. The order was probably created with a different instance of this class earlier. The `price` parameter is missing. To cancel the order, pass a symbol argument and {'price': 12345, 'qty': 1.2345, 'is_ask': 0} in the params argument of cancelOrder.");
- }
- amount = this.safeFloat (params, 'qty');
- if (amount === undefined) {
- // eslint-disable-next-line quotes
- throw new InvalidOrder (this.id + " cancelOrder could not find the order id " + id + " in orders cache. The order was probably created with a different instance of this class earlier. The `qty` (amount) parameter is missing. To cancel the order, pass a symbol argument and {'price': 12345, 'qty': 1.2345, 'is_ask': 0} in the params argument of cancelOrder.");
- }
- side = this.safeFloat (params, 'is_ask');
- if (side === undefined) {
- // eslint-disable-next-line quotes
- throw new InvalidOrder (this.id + " cancelOrder could not find the order id " + id + " in orders cache. The order was probably created with a different instance of this class earlier. The `is_ask` (side) parameter is missing. To cancel the order, pass a symbol argument and {'price': 12345, 'qty': 1.2345, 'is_ask': 0} in the params argument of cancelOrder.");
- }
- } else {
- price = order['price'];
- amount = order['amount'];
- side = (order['side'] === 'buy') ? 0 : 1;
- symbol = order['symbol'];
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ // The returned amount might not be same as the ordered amount. If an order is partially filled, the returned amount means the remaining amount.
+ // For the same reason, the returned amount and remaining are always same, and the returned filled and cost are always zero.
+ if (symbol === undefined) {
+ throw new ExchangeError (this.id + ' allows fetching closed orders with a specific symbol');
}
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'currency': market['id'],
+ };
+ const response = await this.privatePostOrderLimitOrders (this.extend (request, params));
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "limitOrders": [
+ // {
+ // "index": "0",
+ // "orderId": "68665943-1eb5-4e4b-9d76-845fc54f5489",
+ // "timestamp": "1449037367",
+ // "price": "444000.0",
+ // "qty": "0.3456",
+ // "type": "ask",
+ // "feeRate": "-0.0015"
+ // }
+ // ]
+ // }
+ //
+ const limitOrders = this.safeValue (response, 'limitOrders', []);
+ return this.parseOrders (limitOrders, market, since, limit);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'currency': market['id'],
+ };
+ const response = await this.privatePostOrderCompleteOrders (this.extend (request, params));
+ //
+ // despite the name of the endpoint it returns trades which may have a duplicate orderId
+ // https://github.com/ccxt/ccxt/pull/7067
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "completeOrders": [
+ // {
+ // "timestamp": "1416561032",
+ // "price": "419000.0",
+ // "type": "bid",
+ // "qty": "0.001",
+ // "feeRate": "-0.0015",
+ // "fee": "-0.0000015",
+ // "orderId": "E84A1AC2-8088-4FA0-B093-A3BCDB9B3C85"
+ // }
+ // ]
+ // }
+ //
+ const completeOrders = this.safeValue (response, 'completeOrders', []);
+ return this.parseTrades (completeOrders, market, since, limit);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ // eslint-disable-next-line quotes
+ throw new ArgumentsRequired (this.id + " cancelOrder requires a symbol argument. To cancel the order, pass a symbol argument and {'price': 12345, 'qty': 1.2345, 'is_ask': 0} in the params argument of cancelOrder.");
+ }
+ const price = this.safeFloat (params, 'price');
+ const qty = this.safeFloat (params, 'qty');
+ const isAsk = this.safeInteger (params, 'is_ask');
+ if ((price === undefined) || (qty === undefined) || (isAsk === undefined)) {
+ // eslint-disable-next-line quotes
+ throw new ArgumentsRequired (this.id + " cancelOrder requires {'price': 12345, 'qty': 1.2345, 'is_ask': 0} in the params argument.");
+ }
+ await this.loadMarkets ();
const request = {
'order_id': id,
'price': price,
- 'qty': amount,
- 'is_ask': side,
+ 'qty': qty,
+ 'is_ask': isAsk,
'currency': this.marketId (symbol),
};
- this.orders[id]['status'] = 'canceled';
- return await this.privatePostOrderCancel (this.extend (request, params));
+ const response = await this.privatePostOrderCancel (this.extend (request, params));
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0"
+ // }
+ //
+ return response;
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
@@ -43997,12 +53604,12 @@ module.exports = class coinone extends Exchange {
'access_token': this.apiKey,
'nonce': nonce,
}, params));
- const payload = this.stringToBase64 (this.encode (json));
+ const payload = this.stringToBase64 (json);
body = this.decode (payload);
const secret = this.secret.toUpperCase ();
const signature = this.hmac (payload, this.encode (secret), 'sha512');
headers = {
- 'content-type': 'application/json',
+ 'Content-Type': 'application/json',
'X-COINONE-PAYLOAD': payload,
'X-COINONE-SIGNATURE': signature,
};
@@ -44031,7 +53638,7 @@ module.exports = class coinone extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],72:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],72:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -44049,8 +53656,14 @@ module.exports = class coinspot extends Exchange {
'countries': [ 'AU' ], // Australia
'rateLimit': 1000,
'has': {
+ 'cancelOrder': false,
'CORS': false,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/28208429-3cacdf9a-6896-11e7-854e-4c79a772a30f.jpg',
@@ -44082,6 +53695,17 @@ module.exports = class coinspot extends Exchange {
'my/sell',
'my/buy/cancel',
'my/sell/cancel',
+ 'ro/my/balances',
+ 'ro/my/balances/{cointype}',
+ 'ro/my/deposits',
+ 'ro/my/withdrawals',
+ 'ro/my/transactions',
+ 'ro/my/transactions/{cointype}',
+ 'ro/my/transactions/open',
+ 'ro/my/transactions/{cointype}/open',
+ 'ro/my/sendreceive',
+ 'ro/my/affiliatepayments',
+ 'ro/my/referralpayments',
],
},
},
@@ -44161,10 +53785,57 @@ module.exports = class coinspot extends Exchange {
'cointype': market['id'],
};
const response = await this.privatePostOrdersHistory (this.extend (request, params));
+ //
+ // {
+ // "status":"ok",
+ // "orders":[
+ // {"amount":0.00102091,"rate":21549.09999991,"total":21.99969168,"coin":"BTC","solddate":1604890646143,"market":"BTC/AUD"},
+ // ],
+ // }
+ //
const trades = this.safeValue (response, 'orders', []);
return this.parseTrades (trades, market, since, limit);
}
+ parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades
+ //
+ // {
+ // "amount":0.00102091,
+ // "rate":21549.09999991,
+ // "total":21.99969168,
+ // "coin":"BTC",
+ // "solddate":1604890646143,
+ // "market":"BTC/AUD"
+ // }
+ //
+ const price = this.safeFloat (trade, 'rate');
+ const amount = this.safeFloat (trade, 'amount');
+ let cost = this.safeFloat (trade, 'total');
+ if ((cost === undefined) && (price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ const timestamp = this.safeInteger (trade, 'solddate');
+ const marketId = this.safeString (trade, 'market');
+ const symbol = this.safeSymbol (marketId, market, '/');
+ return {
+ 'info': trade,
+ 'id': undefined,
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'order': undefined,
+ 'type': undefined,
+ 'side': undefined,
+ 'takerOrMaker': undefined,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': undefined,
+ };
+ }
+
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const method = 'privatePostMy' + this.capitalize (side);
@@ -44204,1024 +53875,7 @@ module.exports = class coinspot extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],73:[function(require,module,exports){
-'use strict';
-
-// ---------------------------------------------------------------------------
-
-const coinegg = require ('./coinegg.js');
-
-// ---------------------------------------------------------------------------
-
-module.exports = class coolcoin extends coinegg {
- describe () {
- return this.deepExtend (super.describe (), {
- 'id': 'coolcoin',
- 'name': 'CoolCoin',
- 'countries': [ 'HK' ],
- 'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/36770529-be7b1a04-1c5b-11e8-9600-d11f1996b539.jpg',
- 'api': {
- 'web': 'https://www.coolcoin.com/coin',
- 'rest': 'https://www.coolcoin.com/api/v1',
- },
- 'www': 'https://www.coolcoin.com',
- 'doc': 'https://www.coolcoin.com/help.api.html',
- 'fees': 'https://www.coolcoin.com/spend.price.html',
- 'referral': 'https://www.coolcoin.com/user/register?invite_code=bhaega',
- },
- 'fees': {
- 'trading': {
- 'maker': 0.1 / 100,
- 'taker': 0.1 / 100,
- },
- 'funding': {
- 'withdraw': {
- 'BTC': 0.001,
- 'BCH': 0.002,
- 'ETH': 0.01,
- 'ETC': 0.01,
- 'LTC': 0.001,
- 'TBC': '1%',
- 'HSR': '1%',
- 'NEO': '1%',
- 'SDC': '1%',
- 'EOS': '1%',
- 'BTM': '1%',
- 'XAS': '1%',
- 'ACT': '1%',
- 'SAK': '1%',
- 'GCS': '1%',
- 'HCC': '1%',
- 'QTUM': '1%',
- 'GEC': '1%',
- 'TRX': '1%',
- 'IFC': '1%',
- 'PAY': '1%',
- 'PGC': '1%',
- 'KTC': '1%',
- 'INT': '1%',
- 'LSK': '0.5%',
- 'SKT': '1%',
- 'SSS': '1%',
- 'BT1': '1%',
- 'BT2': '1%',
- },
- },
- },
- 'options': {
- 'quoteIds': ['btc', 'usdt'],
- },
- });
- }
-};
-
-},{"./coinegg.js":64}],74:[function(require,module,exports){
-'use strict';
-
-// ---------------------------------------------------------------------------
-
-const Exchange = require ('./base/Exchange');
-const { ArgumentsRequired } = require ('./base/errors');
-
-// ---------------------------------------------------------------------------
-
-module.exports = class coss extends Exchange {
- describe () {
- return this.deepExtend (super.describe (), {
- 'id': 'coss',
- 'name': 'COSS',
- 'countries': [ 'SG', 'NL' ],
- 'rateLimit': 1000,
- 'version': 'v1',
- 'certified': false,
- 'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/50328158-22e53c00-0503-11e9-825c-c5cfd79bfa74.jpg',
- 'api': {
- 'trade': 'https://trade.coss.io/c/api/v1',
- 'engine': 'https://engine.coss.io/api/v1',
- 'public': 'https://trade.coss.io/c/api/v1',
- 'web': 'https://trade.coss.io/c', // undocumented
- 'exchange': 'https://exchange.coss.io/api',
- },
- 'www': 'https://www.coss.io',
- 'doc': 'https://api.coss.io/v1/spec',
- 'referral': 'https://www.coss.io/c/reg?r=OWCMHQVW2Q',
- },
- 'has': {
- 'fetchTrades': true,
- 'fetchTicker': true,
- 'fetchTickers': true,
- 'fetchMarkets': true,
- 'fetchCurrencies': true,
- 'fetchBalance': true,
- 'fetchOrderBook': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOrderTrades': true,
- 'fetchClosedOrders': true,
- 'fetchOpenOrders': true,
- 'fetchOHLCV': true,
- 'createOrder': true,
- 'cancelOrder': true,
- },
- 'timeframes': {
- '1m': '1m',
- '5m': '5m',
- '15m': '15m',
- '30m': '30m',
- '1h': '1h',
- '2h': '2h',
- '4h': '4h',
- '6h': '6h',
- '12h': '12h',
- '1d': '1d',
- '1w': '1w',
- },
- 'api': {
- 'exchange': {
- 'get': [
- 'getmarketsummaries',
- ],
- },
- 'public': {
- 'get': [
- 'market-price',
- 'exchange-info',
- ],
- },
- 'web': {
- 'get': [
- 'coins/getinfo/all', // undocumented
- 'order/symbols', // undocumented
- 'coins/get_base_list', // undocumented
- ],
- },
- 'engine': {
- 'get': [
- 'dp',
- 'ht',
- 'cs',
- ],
- },
- 'trade': {
- 'get': [
- 'ping',
- 'time',
- 'account/balances',
- 'account/details',
- ],
- 'post': [
- 'order/add',
- 'order/details',
- 'order/list/open',
- 'order/list/completed',
- 'order/list/all',
- 'order/trade-detail',
- ],
- 'delete': [
- 'order/cancel',
- ],
- },
- },
- 'fees': {
- 'trading': {
- 'tierBased': true,
- 'percentage': true,
- 'taker': 0.0025,
- 'maker': 0.0,
- },
- 'funding': {
- 'tierBased': false,
- 'percentage': false,
- 'withdraw': {},
- 'deposit': {},
- },
- },
- 'commonCurrencies': {
- 'COS': 'COSS',
- 'COSS': 'COSS.io',
- },
- });
- }
-
- async fetchMarkets (params = {}) {
- const response = await this.publicGetExchangeInfo (params);
- //
- // { timezone: "UTC",
- // server_time: 1545171487108,
- // rate_limits: [ { type: "REQUESTS",
- // interval: "MINUTE",
- // limit: 1000 } ],
- // base_currencies: [ { currency_code: "BTC", minimum_total_order: "0.0001" },
- // { currency_code: "USDT", minimum_total_order: "1" },
- // { currency_code: "EUR", minimum_total_order: "1" } ],
- // coins: [ { currency_code: "ADI",
- // name: "Aditus",
- // minimum_order_amount: "0.00000001" },
- // ...
- // { currency_code: "NPXSXEM",
- // name: "PundiX-XEM",
- // minimum_order_amount: "0.00000001" } ],
- // symbols: [ { symbol: "ADI_BTC",
- // amount_limit_decimal: 0,
- // price_limit_decimal: 8,
- // allow_trading: true },
- // ...
- // { symbol: "ETH_GUSD",
- // amount_limit_decimal: 5,
- // price_limit_decimal: 3,
- // allow_trading: true } ] }
- //
- const result = [];
- const markets = this.safeValue (response, 'symbols', []);
- const baseCurrencies = this.safeValue (response, 'base_currencies', []);
- const baseCurrenciesByIds = this.indexBy (baseCurrencies, 'currency_code');
- const currencies = this.safeValue (response, 'coins', []);
- const currenciesByIds = this.indexBy (currencies, 'currency_code');
- for (let i = 0; i < markets.length; i++) {
- const market = markets[i];
- const marketId = market['symbol'];
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- const symbol = base + '/' + quote;
- const precision = {
- 'amount': this.safeInteger (market, 'amount_limit_decimal'),
- 'price': this.safeInteger (market, 'price_limit_decimal'),
- };
- const active = this.safeValue (market, 'allow_trading', false);
- const baseCurrency = this.safeValue (baseCurrenciesByIds, baseId, {});
- const minCost = this.safeFloat (baseCurrency, 'minimum_total_order');
- const currency = this.safeValue (currenciesByIds, baseId, {});
- const defaultMinAmount = Math.pow (10, -precision['amount']);
- const minAmount = this.safeFloat (currency, 'minimum_order_amount', defaultMinAmount);
- result.push ({
- 'symbol': symbol,
- 'id': marketId,
- 'baseId': baseId,
- 'quoteId': quoteId,
- 'base': base,
- 'quote': quote,
- 'active': active,
- 'precision': precision,
- 'limits': {
- 'amount': {
- 'min': minAmount,
- 'max': undefined,
- },
- 'price': {
- 'min': undefined,
- 'max': undefined,
- },
- 'cost': {
- 'min': minCost,
- 'max': undefined,
- },
- },
- 'info': market,
- });
- }
- return result;
- }
-
- async fetchCurrencies (params = {}) {
- const response = await this.webGetCoinsGetinfoAll (params);
- //
- // [ { currency_code: "VET",
- // name: "VeChain",
- // buy_limit: 0,
- // sell_limit: 0,
- // usdt: 0,
- // transaction_time_limit: 5,
- // status: "trade",
- // withdrawn_fee: "0.6",
- // minimum_withdrawn_amount: "1.2",
- // minimum_deposit_amount: "0.6",
- // minimum_order_amount: "0.00000001",
- // decimal_format: "0.########",
- // token_type: null, // "erc", "eos", "stellar", "tron", "ripple"...
- // buy_at: 0,
- // sell_at: 0,
- // min_rate: 0,
- // max_rate: 0,
- // allow_withdrawn: false,
- // allow_deposit: false,
- // explorer_website_mainnet_link: null,
- // explorer_website_testnet_link: null,
- // deposit_block_confirmation: "6",
- // withdraw_block_confirmation: "0",
- // icon_url: "https://s2.coinmarketcap.com/static/img/coins/32x32/3077.png",
- // is_fiat: false,
- // allow_sell: true,
- // allow_buy: true }]
- //
- const result = {};
- for (let i = 0; i < response.length; i++) {
- const currency = response[i];
- const currencyId = this.safeString (currency, 'currency_code');
- const code = this.safeCurrencyCode (currencyId);
- const name = this.safeString (currency, 'name');
- const allowBuy = this.safeValue (currency, 'allow_buy');
- const allowSell = this.safeValue (currency, 'allow_sell');
- const allowWithdrawals = this.safeValue (currency, 'allow_withdrawn');
- const allowDeposits = this.safeValue (currency, 'allow_deposit');
- const active = allowBuy && allowSell && allowWithdrawals && allowDeposits;
- const fee = this.safeFloat (currency, 'withdrawn_fee');
- const type = this.safeString (currency, 'token_type');
- //
- // decimal_format can be anything...
- //
- // 0.########
- // #.########
- // 0.##
- // '' (empty string)
- // 0.000000
- // null (undefined)
- // 0.0000
- // 0.###
- //
- const decimalFormat = this.safeString (currency, 'decimal_format');
- let precision = 8;
- if (decimalFormat !== undefined) {
- const parts = decimalFormat.split ('.');
- const numParts = parts.length; // transpiler workaround for array lengths
- if (numParts > 1) {
- if (parts[1].length > 1) {
- precision = parts[1].length;
- }
- }
- }
- result[code] = {
- 'id': currencyId,
- 'code': code,
- 'info': currency,
- 'name': name,
- 'active': active,
- 'fee': fee,
- 'precision': precision,
- 'type': type,
- 'limits': {
- 'amount': {
- 'min': this.safeFloat (currency, 'minimum_order_amount'),
- 'max': undefined,
- },
- 'withdraw': {
- 'min': this.safeFloat (currency, 'minimum_withdrawn_amount'),
- 'max': undefined,
- },
- },
- };
- }
- return result;
- }
-
- async fetchBalance (params = {}) {
- await this.loadMarkets ();
- const response = await this.tradeGetAccountBalances (params);
- //
- // [ { currency_code: "ETH",
- // address: "0x6820511d43111a941d3e187b9e36ec64af763bde", // deposit address
- // total: "0.20399125",
- // available: "0.20399125",
- // in_order: "0",
- // memo: null }, // tag, if any
- // { currency_code: "ICX",
- // address: "",
- // total: "0",
- // available: "0",
- // in_order: "0",
- // memo: null } ]
- //
- const result = {};
- for (let i = 0; i < response.length; i++) {
- const balance = response[i];
- const currencyId = this.safeString (balance, 'currency_code');
- const code = this.safeCurrencyCode (currencyId);
- const total = this.safeFloat (balance, 'total');
- const used = this.safeFloat (balance, 'in_order');
- const free = this.safeFloat (balance, 'available');
- result[code] = {
- 'total': total,
- 'used': used,
- 'free': free,
- };
- }
- return this.parseBalance (result);
- }
-
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
- return [
- parseInt (ohlcv[0]), // timestamp
- parseFloat (ohlcv[1]), // Open
- parseFloat (ohlcv[2]), // High
- parseFloat (ohlcv[3]), // Low
- parseFloat (ohlcv[4]), // Close
- parseFloat (ohlcv[5]), // base Volume
- ];
- }
-
- async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'symbol': market['id'],
- 'tt': this.timeframes[timeframe],
- };
- const response = await this.engineGetCs (this.extend (request, params));
- //
- // { tt: "1m",
- // symbol: "ETH_BTC",
- // nextTime: 1545138960000,
- // series: [ [ 1545138960000,
- // "0.02705000",
- // "0.02705000",
- // "0.02705000",
- // "0.02705000",
- // "0.00000000" ],
- // ...
- // [ 1545168900000,
- // "0.02684000",
- // "0.02684000",
- // "0.02684000",
- // "0.02684000",
- // "0.00000000" ] ],
- // limit: 500 }
- //
- return this.parseOHLCVs (response['series'], market, timeframe, since, limit);
- }
-
- async fetchOrderBook (symbol, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const marketId = this.marketId (symbol);
- const request = { 'symbol': marketId };
- // limit argument is not supported on COSS's end
- const response = await this.engineGetDp (this.extend (request, params));
- //
- // { symbol: "COSS_ETH",
- // asks: [ ["0.00065200", "214.15000000"],
- // ["0.00065300", "645.45000000"],
- // ...
- // ["0.00076400", "380.00000000"],
- // ["0.00076900", "25.00000000"] ],
- // limit: 100,
- // bids: [ ["0.00065100", "666.99000000"],
- // ["0.00065000", "1171.93000000"],
- // ...
- // ["0.00037700", "3300.00000000"],
- // ["0.00037600", "2010.82000000"] ],
- // time: 1545180569354 }
- //
- const timestamp = this.safeInteger (response, 'time');
- return this.parseOrderBook (response, timestamp);
- }
-
- parseTicker (ticker, market = undefined) {
- //
- // { MarketName: "COSS-ETH",
- // High: 0.00066,
- // Low: 0.000628,
- // BaseVolume: 131.09652674,
- // Last: 0.000636,
- // TimeStamp: "2018-12-19T05:16:41.369Z",
- // Volume: 206126.6143710692,
- // Ask: "0.00063600",
- // Bid: "0.00063400",
- // PrevDay: 0.000636 }
- //
- const timestamp = this.parse8601 (this.safeString (ticker, 'TimeStamp'));
- let symbol = undefined;
- let marketId = this.safeString (ticker, 'MarketName');
- if (marketId !== undefined) {
- marketId = marketId.replace ('-', '_');
- }
- market = this.safeValue (this.markets_by_id, marketId, market);
- if (market === undefined) {
- if (marketId !== undefined) {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- const previous = this.safeFloat (ticker, 'PrevDay');
- const last = this.safeFloat (ticker, 'Last');
- let change = undefined;
- let percentage = undefined;
- if (last !== undefined) {
- if (previous !== undefined) {
- change = last - previous;
- if (previous > 0) {
- percentage = (change / previous) * 100;
- }
- }
- }
- return {
- 'symbol': symbol,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'high': this.safeFloat (ticker, 'High'),
- 'low': this.safeFloat (ticker, 'Low'),
- 'bid': this.safeFloat (ticker, 'Bid'),
- 'bidVolume': undefined,
- 'ask': this.safeFloat (ticker, 'Ask'),
- 'askVolume': undefined,
- 'vwap': undefined,
- 'open': previous,
- 'close': last,
- 'last': last,
- 'previousClose': undefined,
- 'change': change,
- 'percentage': percentage,
- 'average': undefined,
- 'baseVolume': this.safeFloat (ticker, 'Volume'),
- 'quoteVolume': this.safeFloat (ticker, 'BaseVolume'),
- 'info': ticker,
- };
- }
-
- async fetchTickers (symbols = undefined, params = {}) {
- await this.loadMarkets ();
- const response = await this.exchangeGetGetmarketsummaries (params);
- //
- // { success: true,
- // message: "",
- // result: [ { MarketName: "COSS-ETH",
- // High: 0.00066,
- // Low: 0.000628,
- // BaseVolume: 131.09652674,
- // Last: 0.000636,
- // TimeStamp: "2018-12-19T05:16:41.369Z",
- // Volume: 206126.6143710692,
- // Ask: "0.00063600",
- // Bid: "0.00063400",
- // PrevDay: 0.000636 },
- // ...
- // { MarketName: "XLM-BTC",
- // High: 0.0000309,
- // Low: 0.0000309,
- // BaseVolume: 0,
- // Last: 0.0000309,
- // TimeStamp: "2018-12-19T02:00:02.145Z",
- // Volume: 0,
- // Ask: "0.00003300",
- // Bid: "0.00003090",
- // PrevDay: 0.0000309 } ],
- // volumes: [ { CoinName: "ETH", Volume: 668.1928095999999 }, // these are overall exchange volumes
- // { CoinName: "USD", Volume: 9942.58480324 },
- // { CoinName: "BTC", Volume: 43.749184570000004 },
- // { CoinName: "COSS", Volume: 909909.26644574 },
- // { CoinName: "EUR", Volume: 0 },
- // { CoinName: "TUSD", Volume: 2613.3395026999997 },
- // { CoinName: "USDT", Volume: 1017152.07416519 },
- // { CoinName: "GUSD", Volume: 1.80438 },
- // { CoinName: "XRP", Volume: 15.95508 },
- // { CoinName: "GBP", Volume: 0 },
- // { CoinName: "USDC", Volume: 0 } ],
- // t: 1545196604371 }
- //
- const tickers = this.safeValue (response, 'result', []);
- const result = {};
- for (let i = 0; i < tickers.length; i++) {
- const ticker = this.parseTicker (tickers[i]);
- const symbol = ticker['symbol'];
- result[symbol] = ticker;
- }
- return result;
- }
-
- async fetchTicker (symbol, params = {}) {
- const tickers = await this.fetchTickers ([ symbol ], params);
- return tickers[symbol];
- }
-
- async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'symbol': market['id'],
- };
- const response = await this.engineGetHt (this.extend (request, params));
- //
- // { symbol: "COSS_ETH",
- // limit: 100,
- // history: [ { id: 481321,
- // price: "0.00065100",
- // qty: "272.92000000",
- // isBuyerMaker: false,
- // time: 1545180845019 },
- // { id: 481322,
- // price: "0.00065200",
- // qty: "1.90000000",
- // isBuyerMaker: true,
- // time: 1545180847535 },
- // ...
- // { id: 481420,
- // price: "0.00065300",
- // qty: "2.00000000",
- // isBuyerMaker: true,
- // time: 1545181167702 } ],
- // time: 1545181171274 }
- //
- return this.parseTrades (response['history'], market, since, limit);
- }
-
- parseTradeFee (fee) {
- if (fee === undefined) {
- return fee;
- }
- const parts = fee.split (' ');
- const numParts = parts.length;
- const cost = parts[0];
- let code = undefined;
- if (numParts > 1) {
- code = this.safeCurrencyCode (parts[1]);
- }
- return {
- 'cost': cost,
- 'currency': code,
- };
- }
-
- parseTrade (trade, market = undefined) {
- //
- // fetchTrades (public)
- //
- // { id: 481322,
- // price: "0.00065200",
- // qty: "1.90000000",
- // isBuyerMaker: true,
- // time: 1545180847535 }
- //
- // fetchOrderTrades (private)
- //
- // [ { hex_id: null,
- // symbol: "COSS_ETH",
- // order_id: "ad6f6b47-3def-4add-a5d5-2549a9df1593",
- // order_side: "BUY",
- // price: "0.00065900",
- // quantity: "10",
- // fee: "0.00700000 COSS",
- // additional_fee: "0.00000461 ETH",
- // total: "0.00659000 ETH",
- // timestamp: 1545152356075 } ]
- //
- const id = this.safeString (trade, 'id');
- const timestamp = this.safeInteger (trade, 'time');
- const orderId = this.safeString (trade, 'order_id');
- const side = this.safeStringLower (trade, 'order_side');
- let symbol = undefined;
- const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- market = this.safeValue (this.markets_by_id, marketId, market);
- if (market === undefined) {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- } else if (market !== undefined) {
- symbol = market['symbol'];
- }
- let cost = undefined;
- const price = this.safeFloat (trade, 'price');
- const amount = this.safeFloat2 (trade, 'qty', 'quantity');
- if (amount !== undefined) {
- if (price !== undefined) {
- cost = price * amount;
- }
- }
- const result = {
- 'id': id,
- 'info': trade,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'symbol': symbol,
- 'order': orderId,
- 'type': undefined,
- 'side': side,
- 'takerOrMaker': undefined,
- 'price': price,
- 'amount': amount,
- 'cost': cost,
- 'fee': undefined,
- };
- const fee = this.parseTradeFee (this.safeString (trade, 'fee'));
- if (fee !== undefined) {
- const additionalFee = this.parseTradeFee (this.safeString (trade, 'additional_fee'));
- if (additionalFee === undefined) {
- result['fee'] = fee;
- } else {
- result['fees'] = [
- fee,
- additionalFee,
- ];
- }
- }
- return result;
- }
-
- async fetchOrdersByType (type, symbol = undefined, since = undefined, limit = undefined, params = {}) {
- if (symbol === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument');
- }
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- // 'from_id': 'b2a2d379-f9b6-418b-9414-cbf8330b20d1', // string (uuid), fetchOrders (all orders) only
- // 'page': 0, // different pagination in fetchOpenOrders and fetchClosedOrders
- // 'limit': 50, // optional, max = default = 50
- 'symbol': market['id'], // required
- };
- if (limit !== undefined) {
- request['limit'] = limit; // max = default = 50
- }
- const method = 'tradePostOrderList' + type;
- const response = await this[method] (this.extend (request, params));
- //
- // fetchOrders, fetchClosedOrders
- //
- // [ { hex_id: "5c192784330fe51149f556bb",
- // order_id: "5e46e1b1-93d5-4656-9b43-a5635b08eae9",
- // account_id: "a0c20128-b9e0-484e-9bc8-b8bb86340e5b",
- // order_symbol: "COSS_ETH",
- // order_side: "BUY",
- // status: "filled",
- // createTime: 1545152388019,
- // type: "limit",
- // timeMatching: 0,
- // order_price: "0.00065900",
- // order_size: "10",
- // executed: "10",
- // stop_price: "0.00000000",
- // avg: "0.00065900",
- // total: "0.00659000 ETH" } ]
- //
- // fetchOpenOrders
- //
- // {
- // "total": 2,
- // "list": [
- // {
- // "order_id": "9e5ae4dd-3369-401d-81f5-dff985e1c4ty",
- // "account_id": "9e5ae4dd-3369-401d-81f5-dff985e1c4a6",
- // "order_symbol": "eth-btc",
- // "order_side": "BUY",
- // "status": "OPEN",
- // "createTime": 1538114348750,
- // "type": "limit",
- // "order_price": "0.12345678",
- // "order_size": "10.12345678",
- // "executed": "0",
- // "stop_price": "02.12345678",
- // "avg": "1.12345678",
- // "total": "2.12345678"
- // }
- // ]
- // }
- //
- // the following code is to handle the above difference in response formats
- let orders = undefined;
- if (Array.isArray (response)) {
- orders = response;
- } else {
- orders = this.safeValue (response, 'list', []);
- }
- return this.parseOrders (orders, market, since, limit);
- }
-
- async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- return await this.fetchOrdersByType ('All', symbol, since, limit, params);
- }
-
- async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- return await this.fetchOrdersByType ('Completed', symbol, since, limit, params);
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- return await this.fetchOrdersByType ('Open', symbol, since, limit, params);
- }
-
- async fetchOrder (id, symbol = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'order_id': id,
- };
- const response = await this.tradePostOrderDetails (this.extend (request, params));
- return this.parseOrder (response);
- }
-
- async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- }
- const request = {
- 'order_id': id,
- };
- const response = await this.tradePostOrderTradeDetail (this.extend (request, params));
- //
- // [ { hex_id: null,
- // symbol: "COSS_ETH",
- // order_id: "ad6f6b47-3def-4add-a5d5-2549a9df1593",
- // order_side: "BUY",
- // price: "0.00065900",
- // quantity: "10",
- // fee: "0.00700000 COSS",
- // additional_fee: "0.00000461 ETH",
- // total: "0.00659000 ETH",
- // timestamp: 1545152356075 } ]
- //
- return this.parseTrades (response, market, since, limit);
- }
-
- parseOrderStatus (status) {
- if (status === undefined) {
- return status;
- }
- const statuses = {
- 'OPEN': 'open',
- 'CANCELLED': 'canceled',
- 'FILLED': 'closed',
- 'PARTIAL_FILL': 'closed',
- 'CANCELLING': 'open',
- };
- return this.safeString (statuses, status.toUpperCase (), status);
- }
-
- parseOrder (order, market = undefined) {
- //
- // { hex_id: "5c192784330fe51149f556bb", // missing in fetchOpenOrders
- // order_id: "5e46e1b1-93d5-4656-9b43-a5635b08eae9",
- // account_id: "a0c20128-b9e0-484e-9bc8-b8bb86340e5b",
- // order_symbol: "COSS_ETH", // coss-eth in docs
- // order_side: "BUY",
- // status: "filled",
- // createTime: 1545152388019,
- // type: "limit",
- // timeMatching: 0, // missing in fetchOpenOrders
- // order_price: "0.00065900",
- // order_size: "10",
- // executed: "10",
- // stop_price: "0.00000000",
- // avg: "0.00065900",
- // total: "0.00659000 ETH" }
- //
- const id = this.safeString (order, 'order_id');
- let symbol = undefined;
- let marketId = this.safeString (order, 'order_symbol');
- if (marketId === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- } else {
- // a minor workaround for lowercase eth-btc symbols
- marketId = marketId.toUpperCase ();
- marketId = marketId.replace ('-', '_');
- market = this.safeValue (this.markets_by_id, marketId, market);
- if (market === undefined) {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- } else {
- symbol = market['symbol'];
- }
- }
- const timestamp = this.safeInteger (order, 'createTime');
- const status = this.parseOrderStatus (this.safeString (order, 'status'));
- const price = this.safeFloat (order, 'order_price');
- const filled = this.safeFloat (order, 'executed');
- const type = this.safeString (order, 'type');
- const amount = this.safeFloat (order, 'order_size');
- let remaining = undefined;
- if (amount !== undefined) {
- if (filled !== undefined) {
- remaining = amount - filled;
- }
- }
- const average = this.safeFloat (order, 'avg');
- const side = this.safeStringLower (order, 'order_side');
- const cost = this.safeFloat (order, 'total');
- const fee = undefined;
- const trades = undefined;
- return {
- 'info': order,
- 'id': id,
- 'clientOrderId': undefined,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'lastTradeTimestamp': undefined,
- 'symbol': symbol,
- 'type': type,
- 'side': side,
- 'price': price,
- 'amount': amount,
- 'cost': cost,
- 'average': average,
- 'filled': filled,
- 'remaining': remaining,
- 'status': status,
- 'fee': fee,
- 'trades': trades,
- };
- }
-
- async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'order_symbol': market['id'],
- 'order_size': this.amountToPrecision (symbol, amount),
- 'order_side': side.toUpperCase (),
- 'type': type,
- };
- if (price !== undefined) {
- request['order_price'] = this.priceToPrecision (symbol, price);
- }
- const response = await this.tradePostOrderAdd (this.extend (request, params));
- //
- // {
- // "order_id": "9e5ae4dd-3369-401d-81f5-dff985e1c4ty",
- // "account_id": "9e5ae4dd-3369-401d-81f5-dff985e1c4a6",
- // "order_symbol": "eth-btc",
- // "order_side": "BUY",
- // "status": "OPEN",
- // "createTime": 1538114348750,
- // "type": "limit",
- // "order_price": "0.12345678",
- // "order_size": "10.12345678",
- // "executed": "0",
- // "stop_price": "02.12345678",
- // "avg": "1.12345678",
- // "total": "2.12345678"
- // }
- //
- return this.parseOrder (response, market);
- }
-
- async cancelOrder (id, symbol = undefined, params = {}) {
- if (symbol === undefined) {
- throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
- }
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'order_id': id,
- 'order_symbol': market['id'],
- };
- const response = await this.tradeDeleteOrderCancel (this.extend (request, params));
- //
- // { order_symbol: "COSS_ETH",
- // order_id: "30f2d698-39a0-4b9f-a3a6-a179542373bd",
- // order_size: 0,
- // account_id: "a0c20128-b9e0-484e-9bc8-b8bb86340e5b",
- // timestamp: 1545202728814,
- // recvWindow: null }
- //
- return this.parseOrder (response);
- }
-
- nonce () {
- return this.milliseconds ();
- }
-
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- let url = this.urls['api'][api] + '/' + path;
- if (api === 'trade') {
- this.checkRequiredCredentials ();
- const timestamp = this.nonce ();
- const query = this.extend ({
- 'timestamp': timestamp, // required (int64)
- // 'recvWindow': 10000, // optional (int32)
- }, params);
- let request = undefined;
- if (method === 'GET') {
- request = this.urlencode (query);
- url += '?' + request;
- } else {
- request = this.json (query);
- body = request;
- }
- headers = {
- 'Signature': this.hmac (this.encode (request), this.encode (this.secret)),
- 'Authorization': this.apiKey,
- 'X-Requested-With': 'XMLHttpRequest',
- };
- } else {
- if (Object.keys (params).length) {
- url += '?' + this.urlencode (params);
- }
- }
- return { 'url': url, 'method': method, 'body': body, 'headers': headers };
- }
-};
-
-},{"./base/Exchange":7,"./base/errors":9}],75:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],73:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -45242,21 +53896,28 @@ module.exports = class crex24 extends Exchange {
// new metainfo interface
'has': {
'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
'editOrder': true,
+ 'fetchBalance': true,
'fetchBidsAsks': true,
'fetchClosedOrders': true,
'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
'fetchFundingFees': false,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
'fetchOrders': true,
'fetchOrderTrades': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTradingFee': false, // actually, true, but will be implemented later
'fetchTradingFees': false, // actually, true, but will be implemented later
'fetchTransactions': true,
@@ -45343,9 +54004,15 @@ module.exports = class crex24 extends Exchange {
},
},
'commonCurrencies': {
- 'YOYO': 'YOYOW',
- 'BULL': 'BuySell',
'BCC': 'BCH',
+ 'BIT': 'BitMoney',
+ 'BULL': 'BuySell',
+ 'CREDIT': 'TerraCredit',
+ 'GHOST': 'GHOSTPRISM',
+ 'IQ': 'IQ.Cash',
+ 'PUT': 'PutinCoin',
+ 'UNI': 'Universe',
+ 'YOYO': 'YOYOW',
},
// exchange-specific options
'options': {
@@ -45372,6 +54039,7 @@ module.exports = class crex24 extends Exchange {
'API Key': AuthenticationError, // "API Key '9edc48de-d5b0-4248-8e7e-f59ffcd1c7f1' doesn't exist."
'Insufficient funds': InsufficientFunds, // "Insufficient funds: new order requires 10 ETH which is more than the available balance."
'has been delisted.': BadSymbol, // {"errorDescription":"Instrument '$PAC-BTC' has been delisted."}
+ 'Mandatory parameter': BadRequest, // {"errorDescription":"Mandatory parameter 'feeCurrency' is missing."}
},
},
});
@@ -45599,17 +54267,8 @@ module.exports = class crex24 extends Exchange {
// timestamp: "2018-10-31T09:21:25Z" } ]
//
const timestamp = this.parse8601 (this.safeString (ticker, 'timestamp'));
- let symbol = undefined;
const marketId = this.safeString (ticker, 'instrument');
- market = this.safeValue (this.markets_by_id, marketId, market);
- if (market !== undefined) {
- symbol = market['symbol'];
- } else if (marketId !== undefined) {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const last = this.safeFloat (ticker, 'last');
return {
'symbol': symbol,
@@ -45743,12 +54402,8 @@ module.exports = class crex24 extends Exchange {
const id = this.safeString (trade, 'id');
const side = this.safeString (trade, 'side');
const orderId = this.safeString (trade, 'orderId');
- let symbol = undefined;
const marketId = this.safeString (trade, 'instrument');
- market = this.safeValue (this.markets_by_id, marketId, market);
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
let fee = undefined;
const feeCurrencyId = this.safeString (trade, 'feeCurrency');
const feeCode = this.safeCurrencyCode (feeCurrencyId);
@@ -45800,17 +54455,19 @@ module.exports = class crex24 extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
- // { timestamp: '2019-09-21T10:36:00Z',
- // open: 0.02152,
- // high: 0.02156,
- // low: 0.02152,
- // close: 0.02156,
- // volume: 0.01741259 }
- const date = this.safeString (ohlcv, 'timestamp');
- const timestamp = this.parse8601 (date);
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // timestamp: '2019-09-21T10:36:00Z',
+ // open: 0.02152,
+ // high: 0.02156,
+ // low: 0.02152,
+ // close: 0.02156,
+ // volume: 0.01741259
+ // }
+ //
return [
- timestamp,
+ this.parse8601 (this.safeString (ohlcv, 'timestamp')),
this.safeFloat (ohlcv, 'open'),
this.safeFloat (ohlcv, 'high'),
this.safeFloat (ohlcv, 'low'),
@@ -45830,6 +54487,18 @@ module.exports = class crex24 extends Exchange {
request['limit'] = limit; // Accepted values: 1 - 1000. If the parameter is not specified, the number of results is limited to 100
}
const response = await this.publicGetOhlcv (this.extend (request, params));
+ //
+ // [
+ // {
+ // "timestamp": "2020-06-06T17:36:00Z",
+ // "open": 0.025,
+ // "high": 0.025,
+ // "low": 0.02499,
+ // "close": 0.02499,
+ // "volume": 0.00643127
+ // }
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -45869,21 +54538,8 @@ module.exports = class crex24 extends Exchange {
// }
//
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let symbol = undefined;
const marketId = this.safeString (order, 'instrument');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.parse8601 (this.safeString (order, 'timestamp'));
let price = this.safeFloat (order, 'price');
const amount = this.safeFloat (order, 'volume');
@@ -45926,6 +54582,8 @@ module.exports = class crex24 extends Exchange {
cost = parseFloat (this.costToPrecision (symbol, cost));
}
}
+ const timeInForce = this.safeString (order, 'timeInForce');
+ const stopPrice = this.safeFloat (order, 'stopPrice');
return {
'info': order,
'id': id,
@@ -45935,8 +54593,10 @@ module.exports = class crex24 extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -45986,6 +54646,7 @@ module.exports = class crex24 extends Exchange {
} else {
request['stopPrice'] = this.priceToPrecision (symbol, stopPrice);
}
+ params = this.omit (params, 'stopPrice');
}
const response = await this.tradingPostPlaceOrder (this.extend (request, params));
//
@@ -46457,6 +55118,7 @@ module.exports = class crex24 extends Exchange {
// true - balance will be decreased by amount, whereas [amount - fee] will be transferred to the specified address
// false - amount will be deposited to the specified address, whereas the balance will be decreased by [amount + fee]
// 'includeFee': false, // the default value is false
+ 'feeCurrency': currency['id'], // https://github.com/ccxt/ccxt/issues/7544
};
if (tag !== undefined) {
request['paymentId'] = tag;
@@ -46488,8 +55150,7 @@ module.exports = class crex24 extends Exchange {
body = this.json (params);
auth += body;
}
- const signature = this.stringToBase64 (this.hmac (this.encode (auth), secret, 'sha512', 'binary'));
- headers['X-CREX24-API-SIGN'] = this.decode (signature);
+ headers['X-CREX24-API-SIGN'] = this.hmac (this.encode (auth), secret, 'sha512', 'base64');
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
@@ -46524,7 +55185,1128 @@ module.exports = class crex24 extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],76:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],74:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, BadRequest } = require ('./base/errors');
+const { ROUND, TICK_SIZE } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class currencycom extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'currencycom',
+ 'name': 'Currency.com',
+ 'countries': [ 'BY' ], // Belarus
+ 'rateLimit': 500,
+ 'certified': true,
+ 'pro': true,
+ 'version': 'v1',
+ // new metainfo interface
+ 'has': {
+ 'cancelOrder': true,
+ 'CORS': false,
+ 'createOrder': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTradingFees': true,
+ 'fetchTrades': true,
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '3m': '3m',
+ '5m': '5m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '4h': '4h',
+ '1d': '1d',
+ '1w': '1w',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/83718672-36745c00-a63e-11ea-81a9-677b1f789a4d.jpg',
+ 'api': {
+ 'public': 'https://api-adapter.backend.currency.com/api',
+ 'private': 'https://api-adapter.backend.currency.com/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',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'time',
+ 'exchangeInfo',
+ 'depth',
+ 'aggTrades',
+ 'klines',
+ 'ticker/24hr',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'leverageSettings',
+ 'openOrders',
+ 'tradingPositions',
+ 'account',
+ 'myTrades',
+ ],
+ 'post': [
+ 'order',
+ 'updateTradingPosition',
+ 'updateTradingOrder',
+ 'closeTradingPosition',
+ ],
+ 'delete': [
+ 'order',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': false,
+ 'percentage': true,
+ 'taker': 0.002,
+ 'maker': 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',
+ },
+ },
+ '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,
+ },
+ '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, // 'your time is ahead of server'
+ '-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."}
+ '-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."}
+ '-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': {
+ 'IQ': 'iQIYI',
+ },
+ });
+ }
+
+ nonce () {
+ return this.milliseconds () - this.options['timeDifference'];
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // {
+ // "serverTime": 1590998366609
+ // }
+ //
+ return this.safeInteger (response, 'serverTime');
+ }
+
+ async loadTimeDifference (params = {}) {
+ const response = await this.publicGetTime (params);
+ const after = this.milliseconds ();
+ this.options['timeDifference'] = parseInt (after - response['serverTime']);
+ return this.options['timeDifference'];
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetExchangeInfo (params);
+ //
+ // {
+ // "timezone":"UTC",
+ // "serverTime":1603252990096,
+ // "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":"EVK",
+ // "name":"Evonik",
+ // "status":"BREAK",
+ // "baseAsset":"EVK",
+ // "baseAssetPrecision":3,
+ // "quoteAsset":"EUR",
+ // "quoteAssetId":"EUR",
+ // "quotePrecision":3,
+ // "orderTypes":["LIMIT","MARKET"],
+ // "filters":[
+ // {"filterType":"LOT_SIZE","minQty":"1","maxQty":"27000","stepSize":"1"},
+ // {"filterType":"MIN_NOTIONAL","minNotional":"23"}
+ // ],
+ // "marketType":"SPOT",
+ // "country":"DE",
+ // "sector":"Basic Materials",
+ // "industry":"Diversified Chemicals",
+ // "tradingHours":"UTC; Mon 07:02 - 15:30; Tue 07:02 - 15:30; Wed 07:02 - 15:30; Thu 07:02 - 15:30; Fri 07:02 - 15:30",
+ // "tickSize":0.005,
+ // "tickValue":0.11125,
+ // "exchangeFee":0.05
+ // },
+ // {
+ // "symbol":"BTC/USD_LEVERAGE",
+ // "name":"Bitcoin / USD",
+ // "status":"TRADING",
+ // "baseAsset":"BTC",
+ // "baseAssetPrecision":3,
+ // "quoteAsset":"USD",
+ // "quoteAssetId":"USD_LEVERAGE",
+ // "quotePrecision":3,
+ // "orderTypes":["LIMIT","MARKET","STOP"],
+ // "filters":[
+ // {"filterType":"LOT_SIZE","minQty":"0.001","maxQty":"100","stepSize":"0.001"},
+ // {"filterType":"MIN_NOTIONAL","minNotional":"13"}
+ // ],
+ // "marketType":"LEVERAGE",
+ // "longRate":-0.01,
+ // "shortRate":0.01,
+ // "swapChargeInterval":480,
+ // "country":"",
+ // "sector":"",
+ // "industry":"",
+ // "tradingHours":"UTC; Mon - 21:00, 21:05 -; Tue - 21:00, 21:05 -; Wed - 21:00, 21:05 -; Thu - 21:00, 21:05 -; Fri - 21:00, 22:01 -; Sat - 21:00, 21:05 -; Sun - 20:00, 21:05 -",
+ // "tickSize":0.05,
+ // "tickValue":610.20875,
+ // "makerFee":-0.025,
+ // "takerFee":0.075
+ // },
+ // ]
+ // }
+ //
+ 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;
+ if (id.indexOf ('/') >= 0) {
+ symbol = id;
+ }
+ const filters = this.safeValue (market, 'filters', []);
+ const filtersByType = this.indexBy (filters, 'filterType');
+ const precision = {
+ 'amount': 1 / Math.pow (1, this.safeInteger (market, 'baseAssetPrecision')),
+ 'price': this.safeFloat (market, 'tickSize'),
+ };
+ const status = this.safeString (market, 'status');
+ const active = (status === 'TRADING');
+ let type = this.safeStringLower (market, 'marketType');
+ if (type === 'leverage') {
+ type = 'margin';
+ }
+ const spot = (type === 'spot');
+ const margin = (type === 'margin');
+ const entry = {
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'type': type,
+ 'spot': spot,
+ 'margin': margin,
+ 'info': market,
+ 'active': active,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': Math.pow (10, -precision['amount']),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': -1 * Math.log10 (precision['amount']),
+ 'max': undefined,
+ },
+ },
+ };
+ const exchangeFee = this.safeFloat2 (market, 'exchangeFee', 'tradingFee');
+ const makerFee = this.safeFloat (market, 'makerFee', exchangeFee);
+ const takerFee = this.safeFloat (market, 'takerFee', exchangeFee);
+ if (makerFee !== undefined) {
+ entry['maker'] = makerFee / 100;
+ }
+ if (takerFee !== undefined) {
+ entry['taker'] = takerFee / 100;
+ }
+ if ('PRICE_FILTER' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'PRICE_FILTER', {});
+ entry['precision']['price'] = this.safeFloat (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
+ entry['limits']['price'] = {
+ 'min': this.safeFloat (filter, 'minPrice'),
+ 'max': undefined,
+ };
+ const maxPrice = this.safeFloat (filter, 'maxPrice');
+ if ((maxPrice !== undefined) && (maxPrice > 0)) {
+ entry['limits']['price']['max'] = maxPrice;
+ }
+ }
+ if ('LOT_SIZE' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'LOT_SIZE', {});
+ entry['precision']['amount'] = this.safeFloat (filter, 'stepSize');
+ entry['limits']['amount'] = {
+ 'min': this.safeFloat (filter, 'minQty'),
+ 'max': this.safeFloat (filter, 'maxQty'),
+ };
+ }
+ if ('MARKET_LOT_SIZE' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'MARKET_LOT_SIZE', {});
+ entry['limits']['market'] = {
+ 'min': this.safeFloat (filter, 'minQty'),
+ 'max': this.safeFloat (filter, 'maxQty'),
+ };
+ }
+ if ('MIN_NOTIONAL' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'MIN_NOTIONAL', {});
+ entry['limits']['cost']['min'] = this.safeFloat (filter, 'minNotional');
+ }
+ result.push (entry);
+ }
+ return result;
+ }
+
+ calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) {
+ const market = this.markets[symbol];
+ let key = 'quote';
+ const rate = market[takerOrMaker];
+ let cost = amount * rate;
+ let precision = market['precision']['price'];
+ if (side === 'sell') {
+ cost *= price;
+ } else {
+ key = 'base';
+ precision = market['precision']['amount'];
+ }
+ cost = this.decimalToPrecision (cost, ROUND, precision, this.precisionMode);
+ return {
+ 'type': takerOrMaker,
+ 'currency': market[key],
+ 'rate': rate,
+ 'cost': parseFloat (cost),
+ };
+ }
+
+ async fetchAccounts (params = {}) {
+ const response = await this.privateGetAccount (params);
+ //
+ // {
+ // "makerCommission":0.20,
+ // "takerCommission":0.20,
+ // "buyerCommission":0.20,
+ // "sellerCommission":0.20,
+ // "canTrade":true,
+ // "canWithdraw":true,
+ // "canDeposit":true,
+ // "updateTime":1591056268,
+ // "balances":[
+ // {
+ // "accountId":5470306579272968,
+ // "collateralCurrency":true,
+ // "asset":"ETH",
+ // "free":0.0,
+ // "locked":0.0,
+ // "default":false,
+ // },
+ // ]
+ // }
+ //
+ 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': response,
+ });
+ }
+ return result;
+ }
+
+ async fetchTradingFees (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccount (params);
+ return {
+ 'info': response,
+ 'maker': this.safeFloat (response, 'makerCommission'),
+ 'taker': this.safeFloat (response, 'takerCommission'),
+ };
+ }
+
+ parseBalanceResponse (response) {
+ //
+ // {
+ // "makerCommission":0.20,
+ // "takerCommission":0.20,
+ // "buyerCommission":0.20,
+ // "sellerCommission":0.20,
+ // "canTrade":true,
+ // "canWithdraw":true,
+ // "canDeposit":true,
+ // "updateTime":1591056268,
+ // "balances":[
+ // {
+ // "accountId":5470306579272968,
+ // "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.safeFloat (balance, 'free');
+ account['used'] = this.safeFloat (balance, 'locked');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccount (params);
+ //
+ // {
+ // "makerCommission":0.20,
+ // "takerCommission":0.20,
+ // "buyerCommission":0.20,
+ // "sellerCommission":0.20,
+ // "canTrade":true,
+ // "canWithdraw":true,
+ // "canDeposit":true,
+ // "updateTime":1591056268,
+ // "balances":[
+ // {
+ // "accountId":5470306579272968,
+ // "collateralCurrency":true,
+ // "asset":"ETH",
+ // "free":0.0,
+ // "locked":0.0,
+ // "default":false,
+ // },
+ // ]
+ // }
+ //
+ return this.parseBalanceResponse (response);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 100, max 1000, valid limits 5, 10, 20, 50, 100, 500, 1000, 5000
+ }
+ const response = await this.publicGetDepth (this.extend (request, params));
+ //
+ // {
+ // "lastUpdateId":1590999849037,
+ // "asks":[
+ // [0.02495,60.0000],
+ // [0.02496,120.0000],
+ // [0.02497,240.0000],
+ // ],
+ // "bids":[
+ // [0.02487,60.0000],
+ // [0.02486,120.0000],
+ // [0.02485,240.0000],
+ // ]
+ // }
+ //
+ const orderbook = this.parseOrderBook (response);
+ 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":"EVK",
+ // "highPrice":"22.57",
+ // "lowPrice":"22.16",
+ // "volume":"1",
+ // "quoteVolume":"22.2",
+ // "openTime":1590699364000,
+ // "closeTime":1590785764000
+ // }
+ //
+ const timestamp = this.safeInteger (ticker, 'closeTime');
+ const marketId = this.safeString (ticker, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
+ const last = this.safeFloat (ticker, 'lastPrice');
+ const open = this.safeFloat (ticker, 'openPrice');
+ let average = undefined;
+ if ((open !== undefined) && (last !== undefined)) {
+ average = this.sum (open, last) / 2;
+ }
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'highPrice'),
+ 'low': this.safeFloat (ticker, 'lowPrice'),
+ 'bid': this.safeFloat (ticker, 'bidPrice'),
+ 'bidVolume': this.safeFloat (ticker, 'bidQty'),
+ 'ask': this.safeFloat (ticker, 'askPrice'),
+ 'askVolume': this.safeFloat (ticker, 'askQty'),
+ 'vwap': this.safeFloat (ticker, 'weightedAvgPrice'),
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': this.safeFloat (ticker, 'prevClosePrice'), // previous day close
+ 'change': this.safeFloat (ticker, 'priceChange'),
+ 'percentage': this.safeFloat (ticker, 'priceChangePercent'),
+ 'average': average,
+ 'baseVolume': this.safeFloat (ticker, 'volume'),
+ 'quoteVolume': this.safeFloat (ticker, 'quoteVolume'),
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this.publicGetTicker24hr (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);
+ }
+
+ parseTickers (rawTickers, symbols = undefined) {
+ const tickers = [];
+ for (let i = 0; i < rawTickers.length; i++) {
+ tickers.push (this.parseTicker (rawTickers[i]));
+ }
+ return this.filterByArray (tickers, 'symbol', symbols);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetTicker24hr (params);
+ //
+ // [
+ // {
+ // "symbol":"EVK",
+ // "highPrice":"22.57",
+ // "lowPrice":"22.16",
+ // "volume":"1",
+ // "quoteVolume":"22.2",
+ // "openTime":1590699364000,
+ // "closeTime":1590785764000
+ // }
+ // ]
+ //
+ 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.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ 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.publicGetKlines (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,
+ // "p":"0.02476",
+ // "q":"0.0",
+ // "T":1591001423382,
+ // "m":false
+ // }
+ //
+ // createOrder fills (private)
+ //
+ // {
+ // "price": "9807.05",
+ // "qty": "0.01",
+ // "commission": "0",
+ // "commissionAsset": "dUSD"
+ // }
+ //
+ // fetchMyTrades
+ //
+ // {
+ // "symbol": "BNBBTC",
+ // "id": 28457,
+ // "orderId": 100234,
+ // "price": "4.00000100",
+ // "qty": "12.00000000",
+ // "commission": "10.10000000",
+ // "commissionAsset": "BNB",
+ // "time": 1499865549590,
+ // "isBuyer": true,
+ // "isMaker": false,
+ // "isBestMatch": true
+ // }
+ //
+ const timestamp = this.safeInteger2 (trade, 'T', 'time');
+ const price = this.safeFloat2 (trade, 'p', 'price');
+ const amount = this.safeFloat2 (trade, 'q', 'qty');
+ const id = this.safeString2 (trade, 'a', 'id');
+ let side = undefined;
+ const orderId = this.safeString (trade, 'orderId');
+ if ('m' in trade) {
+ side = trade['m'] ? 'sell' : 'buy'; // this is reversed intentionally
+ } else if ('isBuyerMaker' in trade) {
+ side = trade['isBuyerMaker'] ? 'sell' : 'buy';
+ } else {
+ if ('isBuyer' in trade) {
+ side = (trade['isBuyer']) ? 'buy' : 'sell'; // this is a true side
+ }
+ }
+ let fee = undefined;
+ if ('commission' in trade) {
+ fee = {
+ 'cost': this.safeFloat (trade, 'commission'),
+ 'currency': this.safeCurrencyCode (this.safeString (trade, 'commissionAsset')),
+ };
+ }
+ let takerOrMaker = undefined;
+ if ('isMaker' in trade) {
+ takerOrMaker = trade['isMaker'] ? 'maker' : 'taker';
+ }
+ const marketId = this.safeString (trade, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
+ return {
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'id': id,
+ 'order': orderId,
+ 'type': undefined,
+ 'takerOrMaker': takerOrMaker,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': price * amount,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ 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
+ }
+ const response = await this.publicGetAggTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "a":1658318071,
+ // "p":"0.02476",
+ // "q":"0.0",
+ // "T":1591001423382,
+ // "m":false
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'NEW': 'open',
+ 'PARTIALLY_FILLED': 'open',
+ 'FILLED': 'closed',
+ 'CANCELED': 'canceled',
+ 'PENDING_CANCEL': 'canceling', // currently unused
+ 'REJECTED': 'rejected',
+ 'EXPIRED': 'expired',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // {
+ // "symbol": "BTC/USD",
+ // "orderId": "00000000-0000-0000-0000-0000000c0263",
+ // "clientOrderId": "00000000-0000-0000-0000-0000000c0263",
+ // "transactTime": 1589878206426,
+ // "price": "9825.66210000",
+ // "origQty": "0.01",
+ // "executedQty": "0.01",
+ // "status": "FILLED",
+ // "timeInForce": "FOK",
+ // "type": "MARKET",
+ // "side": "BUY",
+ // "fills": [
+ // {
+ // "price": "9807.05",
+ // "qty": "0.01",
+ // "commission": "0",
+ // "commissionAsset": "dUSD"
+ // }
+ // ]
+ // }
+ //
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '/');
+ let timestamp = undefined;
+ if ('time' in order) {
+ timestamp = this.safeInteger (order, 'time');
+ } else if ('transactTime' in order) {
+ timestamp = this.safeInteger (order, 'transactTime');
+ }
+ let price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'origQty');
+ const filled = this.safeFloat (order, 'executedQty');
+ let remaining = undefined;
+ let cost = this.safeFloat (order, 'cummulativeQuoteQty');
+ if (filled !== undefined) {
+ if (amount !== undefined) {
+ remaining = amount - filled;
+ if (this.options['parseOrderToPrecision']) {
+ remaining = parseFloat (this.amountToPrecision (symbol, remaining));
+ }
+ remaining = Math.max (remaining, 0.0);
+ }
+ if (price !== undefined) {
+ if (cost === undefined) {
+ cost = price * filled;
+ }
+ }
+ }
+ const id = this.safeString (order, 'orderId');
+ const type = this.safeStringLower (order, 'type');
+ if (type === 'market') {
+ if (price === 0.0) {
+ if ((cost !== undefined) && (filled !== undefined)) {
+ if ((cost > 0) && (filled > 0)) {
+ price = cost / filled;
+ }
+ }
+ }
+ }
+ const side = this.safeStringLower (order, 'side');
+ let fee = undefined;
+ let trades = undefined;
+ const fills = this.safeValue (order, 'fills');
+ if (fills !== undefined) {
+ trades = this.parseTrades (fills, market);
+ const numTrades = trades.length;
+ if (numTrades > 0) {
+ cost = trades[0]['cost'];
+ fee = {
+ 'cost': trades[0]['fee']['cost'],
+ 'currency': trades[0]['fee']['currency'],
+ };
+ for (let i = 1; i < trades.length; i++) {
+ cost = this.sum (cost, trades[i]['cost']);
+ fee['cost'] = this.sum (fee['cost'], trades[i]['fee']['cost']);
+ }
+ }
+ }
+ let average = undefined;
+ if (cost !== undefined) {
+ if (filled) {
+ average = cost / filled;
+ }
+ if (this.options['parseOrderToPrecision']) {
+ cost = parseFloat (this.costToPrecision (symbol, cost));
+ }
+ }
+ const timeInForce = this.safeString (order, 'timeInForce');
+ return {
+ 'info': order,
+ 'id': id,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': timeInForce,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': trades,
+ };
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ let accountId = undefined;
+ if (market['margin']) {
+ accountId = this.safeInteger (params, 'accountId');
+ if (accountId === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder requires an accountId parameter for ' + market['type'] + ' market ' + symbol);
+ }
+ }
+ const uppercaseType = type.toUpperCase ();
+ const newOrderRespType = this.safeValue (this.options['newOrderRespType'], type, 'RESULT');
+ const request = {
+ 'symbol': market['id'],
+ 'quantity': this.amountToPrecision (symbol, amount),
+ 'type': uppercaseType,
+ 'side': side.toUpperCase (),
+ 'newOrderRespType': newOrderRespType, // 'RESULT' for full order or 'FULL' for order with fills
+ // 'leverage': 1,
+ // 'accountId': 5470306579272968, // required for leverage markets
+ // 'takeProfit': '123.45',
+ // 'stopLoss': '54.321'
+ // 'guaranteedStopLoss': '54.321',
+ };
+ if (uppercaseType === 'LIMIT') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel, 'FOK' = Fill Or Kill
+ } else if (uppercaseType === 'STOP') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ const response = await this.privatePostOrder (this.extend (request, params));
+ //
+ // {
+ // "symbol": "BTC/USD",
+ // "orderId": "00000000-0000-0000-0000-0000000c0263",
+ // "clientOrderId": "00000000-0000-0000-0000-0000000c0263",
+ // "transactTime": 1589878206426,
+ // "price": "9825.66210000",
+ // "origQty": "0.01",
+ // "executedQty": "0.01",
+ // "status": "FILLED",
+ // "timeInForce": "FOK",
+ // "type": "MARKET",
+ // "side": "BUY",
+ // "fills": [
+ // {
+ // "price": "9807.05",
+ // "qty": "0.01",
+ // "commission": "0",
+ // "commissionAsset": "dUSD"
+ // }
+ // ]
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let market = undefined;
+ const request = {};
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ } else if (this.options['warnOnFetchOpenOrdersWithoutSymbol']) {
+ const symbols = this.symbols;
+ const numSymbols = symbols.length;
+ const fetchOpenOrdersRateLimit = parseInt (numSymbols / 2);
+ throw new ExchangeError (this.id + ' fetchOpenOrders WARNING: fetching open orders without specifying a symbol is rate-limited to one call per ' + fetchOpenOrdersRateLimit.toString () + ' seconds. Do not call this method frequently to avoid ban. Set ' + this.id + '.options["warnOnFetchOpenOrdersWithoutSymbol"] = false to suppress this warning message.');
+ }
+ const response = await this.privateGetOpenOrders (this.extend (request, params));
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const origClientOrderId = this.safeValue (params, 'origClientOrderId');
+ const request = {
+ 'symbol': market['id'],
+ // 'orderId': parseInt (id),
+ // 'origClientOrderId': id,
+ };
+ if (origClientOrderId === undefined) {
+ request['orderId'] = id;
+ } else {
+ request['origClientOrderId'] = origClientOrderId;
+ }
+ const response = await this.privateDeleteOrder (this.extend (request, params));
+ //
+ // {
+ // "symbol":"ETH/USD",
+ // "orderId":"00000000-0000-0000-0000-00000024383b",
+ // "clientOrderId":"00000000-0000-0000-0000-00000024383b",
+ // "price":"150",
+ // "origQty":"0.1",
+ // "executedQty":"0.0",
+ // "status":"CANCELED",
+ // "timeInForce":"GTC",
+ // "type":"LIMIT",
+ // "side":"BUY"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetMyTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "symbol": "BNBBTC",
+ // "id": 28457,
+ // "orderId": 100234,
+ // "price": "4.00000100",
+ // "qty": "12.00000000",
+ // "commission": "10.10000000",
+ // "commissionAsset": "BNB",
+ // "time": 1499865549590,
+ // "isBuyer": true,
+ // "isMaker": false,
+ // "isBestMatch": true
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let url = this.urls['api'][api] + '/' + this.version + '/' + path;
+ if (path === 'historicalTrades') {
+ headers = {
+ 'X-MBX-APIKEY': this.apiKey,
+ };
+ }
+ if (api === 'private') {
+ this.checkRequiredCredentials ();
+ let query = this.urlencode (this.extend ({
+ 'timestamp': this.nonce (),
+ 'recvWindow': this.options['recvWindow'],
+ }, params));
+ const signature = this.hmac (this.encode (query), this.encode (this.secret));
+ query += '&' + 'signature=' + signature;
+ headers = {
+ 'X-MBX-APIKEY': this.apiKey,
+ };
+ if ((method === 'GET') || (method === 'DELETE')) {
+ url += '?' + query;
+ } else {
+ body = query;
+ headers['Content-Type'] = 'application/x-www-form-urlencoded';
+ }
+ } else {
+ if (Object.keys (params).length) {
+ url += '?' + this.urlencode (params);
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if ((httpCode === 418) || (httpCode === 429)) {
+ throw new DDoSProtection (this.id + ' ' + httpCode.toString () + ' ' + reason + ' ' + body);
+ }
+ // error response in a form: { "code": -1013, "msg": "Invalid quantity." }
+ // following block cointains legacy checks against message patterns in "msg" property
+ // will switch "code" checks eventually, when we know all of them
+ if (httpCode >= 400) {
+ if (body.indexOf ('Price * QTY is zero or less') >= 0) {
+ throw new InvalidOrder (this.id + ' order cost = amount * price is zero or less ' + body);
+ }
+ if (body.indexOf ('LOT_SIZE') >= 0) {
+ throw new InvalidOrder (this.id + ' order amount should be evenly divisible by lot size ' + body);
+ }
+ if (body.indexOf ('PRICE_FILTER') >= 0) {
+ throw new InvalidOrder (this.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid float value in general, use this.priceToPrecision (symbol, amount) ' + body);
+ }
+ }
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ //
+ // {"code":-1128,"msg":"Combination of optional parameters invalid."}
+ //
+ const errorCode = this.safeString (response, 'code');
+ if ((errorCode !== undefined) && (errorCode !== '0')) {
+ const feedback = this.id + ' ' + this.json (response);
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ const message = this.safeString (response, 'msg');
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback);
+ }
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],75:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -46545,28 +56327,32 @@ module.exports = class deribit extends Exchange {
'userAgent': undefined,
'rateLimit': 500,
'has': {
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': true,
+ 'createDepositAddress': true,
+ 'createOrder': true,
'editOrder': true,
'fetchBalance': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
'fetchClosedOrders': true,
- 'fetchMyTrades': true,
- 'fetchTickers': true,
- 'fetchOHLCV': true,
'fetchDepositAddress': true,
- 'createDepositAddress': true,
- 'fetchOrderTrades': true,
- 'createOrder': true,
- 'cancelOrder': true,
- 'cancelAllOrders': true,
- 'withdraw': true,
- 'fetchTime': true,
- 'fetchStatus': true,
'fetchDeposits': true,
- 'fetchWithdrawals': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchOrderTrades': true,
+ 'fetchStatus': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTransactions': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1',
@@ -47176,13 +56962,7 @@ module.exports = class deribit extends Exchange {
//
const timestamp = this.safeInteger2 (ticker, 'timestamp', 'creation_timestamp');
const marketId = this.safeString (ticker, 'instrument_name');
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const last = this.safeFloat2 (ticker, 'last_price', 'last');
const stats = this.safeValue (ticker, 'stats', ticker);
return {
@@ -47387,15 +57167,8 @@ module.exports = class deribit extends Exchange {
// }
//
const id = this.safeString (trade, 'trade_id');
- let symbol = undefined;
const marketId = this.safeString (trade, 'instrument_name');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.safeInteger (trade, 'timestamp');
const side = this.safeString (trade, 'direction');
const price = this.safeFloat (trade, 'price');
@@ -47552,6 +57325,15 @@ module.exports = class deribit extends Exchange {
return this.safeString (statuses, status, status);
}
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'good_til_cancelled': 'GTC',
+ 'fill_or_kill': 'FOK',
+ 'immediate_or_cancel': 'IOC',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
+ }
+
parseOrder (order, market = undefined) {
//
// createOrder
@@ -47605,21 +57387,7 @@ module.exports = class deribit extends Exchange {
}
const status = this.parseOrderStatus (this.safeString (order, 'order_state'));
const marketId = this.safeString (order, 'instrument_name');
- let symbol = undefined;
- let base = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- base = market['base'];
- }
- if (market !== undefined) {
- if (symbol === undefined) {
- symbol = market['symbol'];
- }
- if (base === undefined) {
- base = market['base'];
- }
- }
+ market = this.safeMarket (marketId, market);
const side = this.safeStringLower (order, 'direction');
let feeCost = this.safeFloat (order, 'commission');
let fee = undefined;
@@ -47627,7 +57395,7 @@ module.exports = class deribit extends Exchange {
feeCost = Math.abs (feeCost);
fee = {
'cost': feeCost,
- 'currency': base,
+ 'currency': market['base'],
};
}
const type = this.safeString (order, 'order_type');
@@ -47636,6 +57404,8 @@ module.exports = class deribit extends Exchange {
if (trades !== undefined) {
trades = this.parseTrades (trades, market);
}
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'time_in_force'));
+ const stopPrice = undefined;
return {
'info': order,
'id': id,
@@ -47643,10 +57413,12 @@ module.exports = class deribit extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -47738,6 +57510,7 @@ module.exports = class deribit extends Exchange {
} else {
request['stop_price'] = this.priceToPrecision (symbol, stopPrice);
}
+ params = this.omit (params, [ 'stop_price', 'stopPrice' ]);
}
const method = 'privateGet' + this.capitalize (side);
const response = await this[method] (this.extend (request, params));
@@ -48161,6 +57934,86 @@ module.exports = class deribit extends Exchange {
};
}
+ async fetchPosition (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'instrument_name': market['id'],
+ };
+ const response = await this.privateGetPosition (this.extend (request, params));
+ //
+ // {
+ // "jsonrpc": "2.0",
+ // "id": 404,
+ // "result": {
+ // "average_price": 0,
+ // "delta": 0,
+ // "direction": "buy",
+ // "estimated_liquidation_price": 0,
+ // "floating_profit_loss": 0,
+ // "index_price": 3555.86,
+ // "initial_margin": 0,
+ // "instrument_name": "BTC-PERPETUAL",
+ // "leverage": 100,
+ // "kind": "future",
+ // "maintenance_margin": 0,
+ // "mark_price": 3556.62,
+ // "open_orders_margin": 0.000165889,
+ // "realized_profit_loss": 0,
+ // "settlement_price": 3555.44,
+ // "size": 0,
+ // "size_currency": 0,
+ // "total_profit_loss": 0
+ // }
+ // }
+ //
+ // todo unify parsePosition/parsePositions
+ const result = this.safeValue (response, 'result');
+ return result;
+ }
+
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const code = this.codeFromOptions ('fetchPositions');
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privateGetPositions (this.extend (request, params));
+ //
+ // {
+ // "jsonrpc": "2.0",
+ // "id": 2236,
+ // "result": [
+ // {
+ // "average_price": 7440.18,
+ // "delta": 0.006687487,
+ // "direction": "buy",
+ // "estimated_liquidation_price": 1.74,
+ // "floating_profit_loss": 0,
+ // "index_price": 7466.79,
+ // "initial_margin": 0.000197283,
+ // "instrument_name": "BTC-PERPETUAL",
+ // "kind": "future",
+ // "leverage": 34,
+ // "maintenance_margin": 0.000143783,
+ // "mark_price": 7476.65,
+ // "open_orders_margin": 0.000197288,
+ // "realized_funding": -1e-8,
+ // "realized_profit_loss": -9e-9,
+ // "settlement_price": 7476.65,
+ // "size": 50,
+ // "size_currency": 0.006687487,
+ // "total_profit_loss": 0.000032781
+ // }
+ // ]
+ // }
+ //
+ // todo unify parsePosition/parsePositions
+ const result = this.safeValue (response, 'result', []);
+ return result;
+ }
+
async withdraw (code, amount, address, tag = undefined, params = {}) {
this.checkAddress (address);
await this.loadMarkets ();
@@ -48240,13 +58093,13 @@ module.exports = class deribit extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],77:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],76:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { AccountSuspended, BadRequest, BadResponse, NetworkError, DDoSProtection, AuthenticationError, PermissionDenied, ArgumentsRequired, ExchangeError, InsufficientFunds, InvalidOrder, InvalidNonce, OrderNotFound } = require ('./base/errors');
+const { AccountSuspended, BadRequest, BadResponse, NetworkError, DDoSProtection, AuthenticationError, PermissionDenied, ArgumentsRequired, ExchangeError, InsufficientFunds, InvalidOrder, InvalidNonce, OrderNotFound, InvalidAddress, RateLimitExceeded, BadSymbol } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -48259,14 +58112,28 @@ module.exports = class digifinex extends Exchange {
'version': 'v3',
'rateLimit': 900, // 300 for posts
'has': {
+ 'cancelOrder': true,
'cancelOrders': true,
- 'fetchOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchStatus': true,
+ 'fetchTicker': true,
'fetchTickers': true,
- 'fetchMyTrades': true,
- 'fetchLedger': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1',
@@ -48280,14 +58147,14 @@ module.exports = class digifinex extends Exchange {
'1w': '1W',
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/62184319-304e8880-b366-11e9-99fe-8011d6929195.jpg',
- 'api': 'https://openapi.digifinex.vip',
- 'www': 'https://www.digifinex.vip',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87443315-01283a00-c5fe-11ea-8628-c2a0feaf07ac.jpg',
+ 'api': 'https://openapi.digifinex.com',
+ 'www': 'https://www.digifinex.com',
'doc': [
- 'https://docs.digifinex.vip',
+ 'https://docs.digifinex.com',
],
'fees': 'https://digifinex.zendesk.com/hc/en-us/articles/360000328422-Fee-Structure-on-DigiFinex',
- 'referral': 'https://www.digifinex.vip/en-ww/from/DhOzBg/3798****5114',
+ 'referral': 'https://www.digifinex.com/en-ww/from/DhOzBg?channelCode=ljaUPp',
},
'api': {
'v2': {
@@ -48301,12 +58168,15 @@ module.exports = class digifinex extends Exchange {
'kline',
'margin/currencies',
'margin/symbols',
- 'markets', // undocumented
+ 'markets',
'order_book',
'ping',
'spot/symbols',
'time',
'trades',
+ 'trades/symbols',
+ 'ticker',
+ 'currencies', // todo add fetchCurrencies
],
},
'private': {
@@ -48314,6 +58184,7 @@ module.exports = class digifinex extends Exchange {
'{market}/financelog',
'{market}/mytrades',
'{market}/order',
+ '{market}/order/detail', // todo add fetchOrder
'{market}/order/current',
'{market}/order/history',
'margin/assets',
@@ -48330,16 +58201,22 @@ module.exports = class digifinex extends Exchange {
'spot/order',
'spot/order/current',
'spot/order/history',
+ 'deposit/address', // todo add fetchDepositAddress
+ 'deposit/history', // todo add fetchDeposits
+ 'withdraw/history', // todo add fetchWithdrawals
],
'post': [
'{market}/order/cancel',
'{market}/order/new',
+ '{market}/order/batch_new',
'margin/order/cancel',
'margin/order/new',
'margin/position/close',
'spot/order/cancel',
'spot/order/new',
'transfer',
+ 'withdraw/new', // todo add withdraw()
+ 'withdraw/cancel',
],
},
},
@@ -48379,6 +58256,27 @@ module.exports = class digifinex extends Exchange {
'20019': [ BadRequest, 'Wrong trading pair symbol. Correct format:"usdt_btc". Quote asset is in the front' ],
'20020': [ DDoSProtection, "You have violated the API operation trading rules and temporarily forbid trading. At present, we have certain restrictions on the user's transaction rate and withdrawal rate." ],
'50000': [ ExchangeError, 'Exception error' ],
+ '20021': [ BadRequest, 'Invalid currency' ],
+ '20022': [ BadRequest, 'The ending timestamp must be larger than the starting timestamp' ],
+ '20023': [ BadRequest, 'Invalid transfer type' ],
+ '20024': [ BadRequest, 'Invalid amount' ],
+ '20025': [ BadRequest, 'This currency is not transferable at the moment' ],
+ '20026': [ InsufficientFunds, 'Transfer amount exceed your balance' ],
+ '20027': [ PermissionDenied, 'Abnormal account status' ],
+ '20028': [ PermissionDenied, 'Blacklist for transfer' ],
+ '20029': [ PermissionDenied, 'Transfer amount exceed your daily limit' ],
+ '20030': [ BadRequest, 'You have no position on this trading pair' ],
+ '20032': [ PermissionDenied, 'Withdrawal limited' ],
+ '20033': [ BadRequest, 'Wrong Withdrawal ID' ],
+ '20034': [ PermissionDenied, 'Withdrawal service of this crypto has been closed' ],
+ '20035': [ PermissionDenied, 'Withdrawal limit' ],
+ '20036': [ ExchangeError, 'Withdrawal cancellation failed' ],
+ '20037': [ InvalidAddress, 'The withdrawal address, Tag or chain type is not included in the withdrawal management list' ],
+ '20038': [ InvalidAddress, 'The withdrawal address is not on the white list' ],
+ '20039': [ ExchangeError, "Can't be canceled in current status" ],
+ '20040': [ RateLimitExceeded, 'Withdraw too frequently; limitation: 3 times a minute, 100 times a day' ],
+ '20041': [ PermissionDenied, 'Beyond the daily withdrawal limit' ],
+ '20042': [ BadSymbol, 'Current trading pair does not support API trading' ],
},
'broad': {
},
@@ -48389,34 +58287,130 @@ module.exports = class digifinex extends Exchange {
},
'commonCurrencies': {
'BHT': 'Black House Test',
+ 'MBN': 'Mobilian Coin',
+ 'TEL': 'TEL666',
},
});
}
- async fetchMarketsByType (type, params = {}) {
- const method = 'publicGet' + this.capitalize (type) + 'Symbols';
- const response = await this[method] (params);
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCurrencies (params);
//
// {
- // "symbol_list": [
+ // "data":[
+ // {
+ // "deposit_status":1,
+ // "min_deposit_amount":10,
+ // "withdraw_fee_rate":0,
+ // "min_withdraw_amount":10,
+ // "min_withdraw_fee":5,
+ // "currency":"USDT",
+ // "withdraw_status":0,
+ // "chain":"OMNI"
+ // },
+ // {
+ // "deposit_status":1,
+ // "min_deposit_amount":10,
+ // "withdraw_fee_rate":0,
+ // "min_withdraw_amount":10,
+ // "min_withdraw_fee":3,
+ // "currency":"USDT",
+ // "withdraw_status":1,
+ // "chain":"ERC20"
+ // },
+ // {
+ // "deposit_status":0,
+ // "min_deposit_amount":0,
+ // "withdraw_fee_rate":0,
+ // "min_withdraw_amount":0,
+ // "min_withdraw_fee":0,
+ // "currency":"DGF13",
+ // "withdraw_status":0,
+ // "chain":""
+ // },
+ // ],
+ // "code":200
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = {};
+ for (let i = 0; i < data.length; i++) {
+ const currency = data[i];
+ const id = this.safeString (currency, 'currency');
+ const code = this.safeCurrencyCode (id);
+ const depositStatus = this.safeValue (currency, 'deposit_status', 1);
+ const withdrawStatus = this.safeValue (currency, 'withdraw_status', 1);
+ const active = depositStatus && withdrawStatus;
+ const fee = this.safeFloat (currency, 'withdraw_fee_rate');
+ if (code in result) {
+ if (Array.isArray (result[code]['info'])) {
+ result[code]['info'].push (currency);
+ } else {
+ result[code]['info'] = [ result[code]['info'], currency ];
+ }
+ } else {
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': currency,
+ 'type': undefined,
+ 'name': undefined,
+ 'active': active,
+ 'fee': fee,
+ 'precision': 8, // todo fix hardcoded value
+ 'limits': {
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (currency, 'min_withdraw_amount'),
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ }
+ return result;
+ }
+
+ async fetchMarkets (params = {}) {
+ const options = this.safeValue (this.options, 'fetchMarkets', {});
+ const method = this.safeString (options, 'method', 'fetch_markets_v2');
+ return await this[method] (params);
+ }
+
+ async fetchMarketsV2 (params = {}) {
+ const response = await this.publicGetTradesSymbols (params);
+ //
+ // {
+ // "symbol_list":[
// {
// "order_types":["LIMIT","MARKET"],
// "quote_asset":"USDT",
// "minimum_value":2,
// "amount_precision":4,
// "status":"TRADING",
- // "minimum_amount":0.001,
- // "symbol":"LTC_USDT",
- // "margin_rate":0.3,
+ // "minimum_amount":0.0001,
+ // "symbol":"BTC_USDT",
+ // "is_allow":1,
// "zone":"MAIN",
- // "base_asset":"LTC",
+ // "base_asset":"BTC",
// "price_precision":2
- // },
+ // }
// ],
// "code":0
// }
//
- const markets = this.safeValue (response, 'symbols_list', []);
+ const markets = this.safeValue (response, 'symbol_list', []);
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
@@ -48454,7 +58448,9 @@ module.exports = class digifinex extends Exchange {
// const status = this.safeString (market, 'status');
// const active = (status === 'TRADING');
//
- const active = undefined;
+ const isAllowed = this.safeValue (market, 'is_allow', 1);
+ const active = isAllowed ? true : false;
+ const type = 'spot';
const spot = (type === 'spot');
const margin = (type === 'margin');
result.push ({
@@ -48476,7 +58472,7 @@ module.exports = class digifinex extends Exchange {
return result;
}
- async fetchMarkets (params = {}) {
+ async fetchMarketsV1 (params = {}) {
const response = await this.publicGetMarkets (params);
//
// {
@@ -48637,20 +58633,12 @@ module.exports = class digifinex extends Exchange {
'date': date,
}, tickers[reversedMarketId]);
const [ quoteId, baseId ] = reversedMarketId.split ('_');
- const marketId = baseId + '_' + quoteId;
- let market = undefined;
- let symbol = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ const marketId = baseId.toUpperCase () + '_' + quoteId.toUpperCase ();
+ const market = this.safeMarket (marketId, undefined, '_');
+ const symbol = market['symbol'];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -48661,7 +58649,7 @@ module.exports = class digifinex extends Exchange {
await this.loadMarkets ();
const market = this.market (symbol);
// reversed base/quote in v2
- const marketId = market['quoteId'] + '_' + market['baseId'];
+ const marketId = market['quoteId'].toLowerCase () + '_' + market['baseId'].toLowerCase ();
const request = {
'symbol': marketId,
'apiKey': apiKey,
@@ -48778,24 +58766,8 @@ module.exports = class digifinex extends Exchange {
cost = price * amount;
}
}
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[market];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const takerOrMaker = this.safeValue (trade, 'is_maker');
const feeCost = this.safeFloat (trade, 'fee');
let fee = undefined;
@@ -48824,6 +58796,32 @@ module.exports = class digifinex extends Exchange {
};
}
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // {
+ // "server_time": 1589873762,
+ // "code": 0
+ // }
+ //
+ return this.safeTimestamp (response, 'server_time');
+ }
+
+ async fetchStatus (params = {}) {
+ await this.publicGetPing (params);
+ //
+ // {
+ // "msg": "pong",
+ // "code": 0
+ // }
+ //
+ this.status = this.extend (this.status, {
+ 'status': 'ok',
+ 'updated': this.milliseconds (),
+ });
+ return this.status;
+ }
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -48860,14 +58858,24 @@ module.exports = class digifinex extends Exchange {
return this.parseTrades (data, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1556712900,
+ // 2205.899,
+ // 0.029967,
+ // 0.02997,
+ // 0.029871,
+ // 0.029927
+ // ]
+ //
return [
- ohlcv[0] * 1000, // timestamp
- ohlcv[5], // open
- ohlcv[3], // high
- ohlcv[4], // low
- ohlcv[2], // close
- ohlcv[1], // volume
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 5), // open
+ this.safeFloat (ohlcv, 3), // high
+ this.safeFloat (ohlcv, 4), // low
+ this.safeFloat (ohlcv, 2), // close
+ this.safeFloat (ohlcv, 1), // volume
];
}
@@ -49056,25 +59064,8 @@ module.exports = class digifinex extends Exchange {
}
}
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- if (market === undefined) {
- const exchange = order['symbol'].toUpperCase ();
- if (exchange in this.markets_by_id) {
- market = this.markets_by_id[exchange];
- }
- }
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const amount = this.safeFloat (order, 'amount');
const filled = this.safeFloat (order, 'executed_amount');
const price = this.safeFloat (order, 'price');
@@ -49098,8 +59089,10 @@ module.exports = class digifinex extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': filled,
'remaining': remaining,
@@ -49230,8 +59223,12 @@ module.exports = class digifinex extends Exchange {
// ]
// }
//
- const data = this.safeValue (response, 'data', {});
- return this.parseOrder (data, market);
+ const data = this.safeValue (response, 'data', []);
+ const order = this.safeValue (data, 0);
+ if (order === undefined) {
+ throw new OrderNotFound (this.id + ' fetchOrder() order ' + id + ' not found');
+ }
+ return this.parseOrder (order, market);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -49361,6 +59358,218 @@ module.exports = class digifinex extends Exchange {
return this.parseLedger (items, currency, since, limit);
}
+ parseDepositAddresses (addresses) {
+ const result = {};
+ for (let i = 0; i < addresses.length; i++) {
+ const address = this.parseDepositAddress (addresses[i]);
+ const code = address['currency'];
+ result[code] = address;
+ }
+ return result;
+ }
+
+ parseDepositAddress (depositAddress, currency = undefined) {
+ //
+ // {
+ // "addressTag":"",
+ // "address":"0xf1104d9f8624f89775a3e9d480fc0e75a8ef4373",
+ // "currency":"USDT",
+ // "chain":"ERC20"
+ // }
+ //
+ const address = this.safeString (depositAddress, 'address');
+ const tag = this.safeString (depositAddress, 'addressTag');
+ const currencyId = this.safeStringUpper (depositAddress, 'currency');
+ const code = this.safeCurrencCode (currencyId);
+ return {
+ 'info': depositAddress,
+ 'code': code,
+ 'address': address,
+ 'tag': tag,
+ };
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privateGetDepositAddress (this.extend (request, params));
+ //
+ // {
+ // "data":[
+ // {
+ // "addressTag":"",
+ // "address":"0xf1104d9f8624f89775a3e9d480fc0e75a8ef4373",
+ // "currency":"USDT",
+ // "chain":"ERC20"
+ // }
+ // ],
+ // "code":200
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const addresses = this.parseDepositAddresses (data);
+ const address = this.safeValue (addresses, code);
+ if (address === undefined) {
+ throw new InvalidAddress (this.id + ' fetchDepositAddress did not return an address for ' + code + ' - create the deposit address in the user settings on the exchange website first.');
+ }
+ return address;
+ }
+
+ async fetchTransactionsByType (type, code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let currency = undefined;
+ const request = {
+ // 'currency': currency['id'],
+ // 'from': 'fromId', // When direct is' prev ', from is 1, returning from old to new ascending, when direct is' next ', from is the ID of the most recent record, returned from the old descending order
+ // 'size': 100, // default 100, max 500
+ // 'direct': 'prev', // "prev" ascending, "next" descending
+ };
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency'] = currency['id'];
+ }
+ if (limit !== undefined) {
+ request['size'] = Math.min (500, limit);
+ }
+ const method = (type === 'deposit') ? 'privateGetDepositHistory' : 'privateGetWithdrawHistory';
+ const response = await this[method] (this.extend (request, params));
+ //
+ // {
+ // "code": 200,
+ // "data": [
+ // {
+ // "id": 1171,
+ // "currency": "xrp",
+ // "hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
+ // "chain": "",
+ // "amount": 7.457467,
+ // "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
+ // "memo": "100040",
+ // "fee": 0,
+ // "state": "safe",
+ // "created_date": "2020-04-20 11:23:00",
+ // "finished_date": "2020-04-20 13:23:00"
+ // },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTransactions (data, currency, since, limit, { 'type': type });
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsByType ('deposit', code, since, limit, params);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsByType ('withdrawal', code, since, limit, params);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ '0': 'pending', // Email Sent
+ '1': 'canceled', // Cancelled (different from 1 = ok in deposits)
+ '2': 'pending', // Awaiting Approval
+ '3': 'failed', // Rejected
+ '4': 'pending', // Processing
+ '5': 'failed', // Failure
+ '6': 'ok', // Completed
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // withdraw
+ //
+ // {
+ // "code": 200,
+ // "withdraw_id": 700
+ // }
+ //
+ // fetchDeposits, fetchWithdrawals
+ //
+ // {
+ // "id": 1171,
+ // "currency": "xrp",
+ // "hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
+ // "chain": "",
+ // "amount": 7.457467,
+ // "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
+ // "memo": "100040",
+ // "fee": 0,
+ // "state": "safe",
+ // "created_date": "2020-04-20 11:23:00",
+ // "finished_date": "2020-04-20 13:23:00"
+ // }
+ //
+ const id = this.safeString2 (transaction, 'id', 'withdraw_id');
+ const address = this.safeString (transaction, 'address');
+ let tag = this.safeString (transaction, 'memo'); // set but unused
+ if (tag !== undefined) {
+ if (tag.length < 1) {
+ tag = undefined;
+ }
+ }
+ const txid = this.safeString (transaction, 'hash');
+ const currencyId = this.safeStringUpper (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const timestamp = this.parse8601 (this.safeString (transaction, 'created_date'));
+ const updated = this.parse8601 (this.safeString (transaction, 'finished_date'));
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'state'));
+ const amount = this.safeFloat (transaction, 'amount');
+ const feeCost = this.safeFloat (transaction, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ fee = { 'currency': code, 'cost': feeCost };
+ }
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'address': address,
+ 'addressTo': address,
+ 'addressFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'tagFrom': undefined,
+ 'type': undefined,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': updated,
+ 'fee': fee,
+ };
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ // 'chain': 'ERC20', 'OMNI', 'TRC20', // required for USDT
+ 'address': address,
+ 'amount': parseFloat (amount),
+ 'currency': currency['id'],
+ };
+ if (tag !== undefined) {
+ request['memo'] = tag;
+ }
+ const response = await this.privatePostWithdrawNew (this.extend (request, params));
+ //
+ // {
+ // "code": 200,
+ // "withdraw_id": 700
+ // }
+ //
+ return this.parseTransaction (response, currency);
+ }
+
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
const version = (api === 'v2') ? api : this.version;
let url = this.urls['api'] + '/' + version + '/' + this.implodeParams (path, params);
@@ -49396,17 +59605,12 @@ module.exports = class digifinex extends Exchange {
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
- dateUTC8 (timestampMS) {
- const timedelta = this.safeValue (this.options, 'timedelta', 8 * 60 * 60 * 1000); // eight hours
- return this.ymd (timestampMS + timedelta);
- }
-
handleErrors (statusCode, statusText, url, method, responseHeaders, responseBody, response, requestHeaders, requestBody) {
if (!response) {
return; // fall back to default error handler
}
const code = this.safeString (response, 'code');
- if (code === '0') {
+ if ((code === '0') || (code === '200')) {
return; // no error
}
const feedback = this.id + ' ' + responseBody;
@@ -49419,7 +59623,7 @@ module.exports = class digifinex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],78:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],77:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -49438,31 +59642,38 @@ module.exports = class dsx extends Exchange {
'rateLimit': 1500,
'version': 'v3',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'createMarketOrder': false,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': false,
- 'fetchOrderBooks': false,
'createDepositAddress': true,
+ 'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': false,
'fetchDepositAddress': true,
- 'fetchTransactions': true,
- 'fetchTickers': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrderBooks': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTransactions': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/51840849/76909626-cb2bb100-68bc-11ea-99e0-28ba54f04792.jpg',
'api': {
- 'public': 'https://dsx.uk/mapi', // market data
- 'private': 'https://dsx.uk/tapi', // trading
- 'dwapi': 'https://dsx.uk/dwapi', // deposit/withdraw
+ 'public': 'https://dsxglobal.com/mapi', // market data
+ 'private': 'https://dsxglobal.com/tapi', // trading
+ 'dwapi': 'https://dsxglobal.com/dwapi', // deposit/withdraw
},
- 'www': 'https://dsx.uk',
+ 'www': 'https://dsxglobal.com',
'doc': [
- 'https://dsx.uk/developers/publicApi',
+ 'https://dsxglobal.com/developers/publicApi',
],
},
'fees': {
@@ -49539,6 +59750,7 @@ module.exports = class dsx extends Exchange {
'data unavailable': ExchangeNotAvailable,
'external service unavailable': ExchangeNotAvailable,
'nonce is invalid': InvalidNonce, // {"success":0,"error":"Parameter: nonce is invalid"}
+ 'Incorrect volume': InvalidOrder, // {"success": 0,"error":"Order was rejected. Incorrect volume."}
},
},
'options': {
@@ -49961,7 +60173,7 @@ module.exports = class dsx extends Exchange {
}
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -49988,7 +60200,7 @@ module.exports = class dsx extends Exchange {
return this.parseTrades (response[market['id']], market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// "high" : 0.01955,
@@ -50136,9 +60348,6 @@ module.exports = class dsx extends Exchange {
'filled': filled,
'fee': undefined,
// 'trades': this.parseTrades (order['trades'], market),
- 'clientOrderId': undefined,
- 'average': undefined,
- 'trades': undefined,
};
}
@@ -50256,8 +60465,10 @@ module.exports = class dsx extends Exchange {
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
'type': orderType,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'remaining': remaining,
@@ -50265,7 +60476,6 @@ module.exports = class dsx extends Exchange {
'status': status,
'fee': fee,
'trades': trades,
- 'average': undefined,
};
}
@@ -50387,9 +60597,6 @@ module.exports = class dsx extends Exchange {
'orderId': id,
};
const response = await this.privatePostOrderCancel (this.extend (request, params));
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- }
return response;
}
@@ -50610,7 +60817,7 @@ module.exports = class dsx extends Exchange {
body = this.urlencode (this.extend ({
'nonce': nonce,
}, query));
- const signature = this.decode (this.hmac (this.encode (body), this.encode (this.secret), 'sha512', 'base64'));
+ const signature = this.hmac (this.encode (body), this.encode (this.secret), 'sha512', 'base64');
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Key': this.apiKey,
@@ -50691,7 +60898,1150 @@ module.exports = class dsx extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],79:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],78:[function(require,module,exports){
+'use strict';
+
+// ----------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ArgumentsRequired, InvalidOrder, ExchangeError, BadRequest, BadSymbol } = require ('./base/errors');
+const { TRUNCATE, SIGNIFICANT_DIGITS } = require ('./base/functions/number');
+
+// ----------------------------------------------------------------------------
+
+module.exports = class eterbase extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'eterbase',
+ 'name': 'Eterbase',
+ 'countries': [ 'SK' ], // Slovakia
+ 'rateLimit': 500,
+ 'version': 'v1',
+ 'certified': true,
+ 'has': {
+ 'CORS': false,
+ 'publicAPI': true,
+ 'privateAPI': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'deposit': false,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': false,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
+ },
+ 'timeframes': {
+ '1m': '1',
+ '5m': '5',
+ '15m': '15',
+ '1h': '60',
+ '4h': '240',
+ '1d': '1440',
+ '1w': '10080',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/82067900-faeb0f80-96d9-11ea-9f22-0071cfcb9871.jpg',
+ 'api': 'https://api.eterbase.exchange',
+ 'www': 'https://www.eterbase.com',
+ 'doc': 'https://developers.eterbase.exchange',
+ 'fees': 'https://www.eterbase.com/exchange/fees',
+ 'referral': 'https://eterbase.exchange/invite/1wjjh4Pe',
+ },
+ 'api': {
+ 'markets': {
+ 'get': [
+ '{id}/order-book',
+ ],
+ },
+ 'public': {
+ 'get': [
+ 'ping',
+ 'assets',
+ 'markets',
+ 'tickers',
+ 'tickers/{id}/ticker',
+ 'markets/{id}/trades',
+ 'markets/{id}/ohlcv',
+ 'wstoken',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'accounts/{id}/balances',
+ 'accounts/{id}/orders',
+ 'accounts/{id}/fills',
+ 'orders/{id}/fills',
+ 'orders/{id}',
+ ],
+ 'post': [
+ 'orders',
+ 'accounts/{id}/withdrawals',
+ ],
+ 'delete': [
+ 'orders/{id}',
+ ],
+ },
+ 'feed': {
+ 'get': [
+ 'feed',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.35 / 100,
+ 'maker': 0.35 / 100,
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ 'uid': true,
+ },
+ 'precisionMode': SIGNIFICANT_DIGITS,
+ 'options': {
+ 'createMarketBuyOrderRequiresPrice': true,
+ },
+ 'exceptions': {
+ 'exact': {
+ 'Invalid cost': InvalidOrder, // {"message":"Invalid cost","_links":{"self":{"href":"/orders","templated":false}}}
+ 'Invalid order ID': InvalidOrder, // {"message":"Invalid order ID","_links":{"self":{"href":"/orders/4a151805-d594-4a96-9d64-e3984f2441f7","templated":false}}}
+ 'Invalid market !': BadSymbol, // {"message":"Invalid market !","_links":{"self":{"href":"/markets/300/order-book","templated":false}}}
+ },
+ 'broad': {
+ 'Failed to convert argument': BadRequest,
+ },
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetPing (params);
+ //
+ // { "pong": 1556354416582 }
+ //
+ return this.safeInteger (response, 'pong');
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetMarkets (params);
+ //
+ // [
+ // {
+ // "id":33,
+ // "symbol":"ETHUSDT",
+ // "base":"ETH",
+ // "quote":"USDT",
+ // "priceSigDigs":5,
+ // "qtySigDigs":8,
+ // "costSigDigs":8,
+ // "verificationLevelUser":1,
+ // "verificationLevelCorporate":11,
+ // "group":"USD",
+ // "tradingRules":[
+ // {"attribute":"Qty","condition":"Min","value":0.006},
+ // {"attribute":"Qty","condition":"Max","value":1000},
+ // {"attribute":"Cost","condition":"Min","value":1},
+ // {"attribute":"Cost","condition":"Max","value":210000}
+ // ],
+ // "allowedOrderTypes":[1,2,3,4],
+ // "state":"Trading"
+ // }
+ // ]
+ //
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const market = this.parseMarket (response[i]);
+ result.push (market);
+ }
+ return result;
+ }
+
+ parseMarket (market) {
+ //
+ // {
+ // "id":33,
+ // "symbol":"ETHUSDT",
+ // "base":"ETH",
+ // "quote":"USDT",
+ // "priceSigDigs":5,
+ // "qtySigDigs":8,
+ // "costSigDigs":8,
+ // "verificationLevelUser":1,
+ // "verificationLevelCorporate":11,
+ // "group":"USD",
+ // "tradingRules":[
+ // {"attribute":"Qty","condition":"Min","value":0.006},
+ // {"attribute":"Qty","condition":"Max","value":1000},
+ // {"attribute":"Cost","condition":"Min","value":1},
+ // {"attribute":"Cost","condition":"Max","value":210000}
+ // ],
+ // "allowedOrderTypes":[1,2,3,4],
+ // "state":"Trading"
+ // }
+ //
+ const id = this.safeString (market, 'id');
+ // const numericId = this.safeString (market, 'id');
+ const baseId = this.safeString (market, 'base');
+ const quoteId = this.safeString (market, 'quote');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const state = this.safeString (market, 'state');
+ const active = (state === 'Trading');
+ const precision = {
+ 'price': this.safeInteger (market, 'priceSigDigs'),
+ 'amount': this.safeInteger (market, 'qtySigDigs'),
+ 'cost': this.safeInteger (market, 'costSigDigs'),
+ };
+ const rules = this.safeValue (market, 'tradingRules', []);
+ let minAmount = undefined;
+ let maxAmount = undefined;
+ let minCost = undefined;
+ let maxCost = undefined;
+ for (let i = 0; i < rules.length; i++) {
+ const rule = rules[i];
+ const attribute = this.safeString (rule, 'attribute');
+ const condition = this.safeString (rule, 'condition');
+ const value = this.safeFloat (rule, 'value');
+ if ((attribute === 'Qty') && (condition === 'Min')) {
+ minAmount = value;
+ } else if ((attribute === 'Qty') && (condition === 'Max')) {
+ maxAmount = value;
+ } else if ((attribute === 'Cost') && (condition === 'Min')) {
+ minCost = value;
+ } else if ((attribute === 'Cost') && (condition === 'Max')) {
+ maxCost = value;
+ }
+ }
+ return {
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'info': market,
+ 'active': active,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': minAmount,
+ 'max': maxAmount,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': minCost,
+ 'max': maxCost,
+ },
+ },
+ };
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetAssets (params);
+ //
+ // [
+ // {
+ // "id":"LINK",
+ // "name":"ChainLink Token",
+ // "precisionDisplay":8,
+ // "precisionMax":18,
+ // "precisionBasis":1000000000000000000,
+ // "precisionStep":1,
+ // "verificationLevelMin":"null",
+ // "cmcId":"LINK",
+ // "txnUrl":"https://etherscan.io/tx/{txnId}",
+ // "state":"Active",
+ // "type":"Crypto",
+ // "isReference":false,
+ // "withdrawalMin":"0",
+ // "withdrawalMax":"50587",
+ // "withdrawalFee":"0.55",
+ // "depositEnabled":true,
+ // "withdrawalEnabled":true,
+ // "description":"",
+ // "coingeckoUrl":"https://www.coingecko.com/en/coins/chainlink",
+ // "coinmarketcapUrl":"https://coinmarketcap.com/currencies/chainlink",
+ // "eterbaseUrl":"https://www.eterbase.com/system-status/LINK",
+ // "explorerUrl":"https://etherscan.io/token/0x514910771af9ca656af840dff83e8264ecf986ca",
+ // "withdrawalMemoAllowed":false,
+ // "countries":[],
+ // "networks":[]
+ // }
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const currency = response[i];
+ const id = this.safeString (currency, 'id');
+ const precision = this.safeInteger (currency, 'precisionDisplay');
+ const code = this.safeCurrencyCode (id);
+ const depositEnabled = this.safeValue (currency, 'depositEnabled');
+ const withdrawalEnabled = this.safeValue (currency, 'withdrawalEnabled');
+ const state = this.safeString (currency, 'state');
+ const active = depositEnabled && withdrawalEnabled && (state === 'Active');
+ const type = this.safeStringLower (currency, 'type');
+ const name = this.safeString (currency, 'name');
+ result[code] = {
+ 'id': id,
+ 'info': currency,
+ 'code': code,
+ 'type': type,
+ 'name': name,
+ 'active': active,
+ 'fee': this.safeFloat (currency, 'withdrawalFee'),
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': Math.pow (10, -precision),
+ 'max': Math.pow (10, precision),
+ },
+ 'price': {
+ 'min': Math.pow (10, -precision),
+ 'max': Math.pow (10, precision),
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (currency, 'withdrawalMin'),
+ 'max': this.safeFloat (currency, 'withdrawalMax'),
+ },
+ },
+ };
+ }
+ return result;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker
+ //
+ // {
+ // "time":1588778516608,
+ // "marketId":250,
+ // "symbol": "ETHUSDT",
+ // "price":0.0,
+ // "change":0.0,
+ // "volumeBase":0.0,
+ // "volume":0.0,
+ // "low":0.0,
+ // "high":0.0,
+ // }
+ //
+ const marketId = this.safeString (ticker, 'marketId');
+ const symbol = this.safeSymbol (marketId, market);
+ const timestamp = this.safeInteger (ticker, 'time');
+ const last = this.safeFloat (ticker, 'price');
+ const baseVolume = this.safeFloat (ticker, 'volumeBase');
+ const quoteVolume = this.safeFloat (ticker, 'volume');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ const percentage = this.safeFloat (ticker, 'change');
+ const result = {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': undefined,
+ 'bidVolume': undefined,
+ 'ask': undefined,
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': undefined,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined, // previous day close
+ 'change': undefined,
+ 'percentage': percentage,
+ 'average': undefined,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ return result;
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'id': market['id'],
+ };
+ const response = await this.publicGetTickersIdTicker (this.extend (request, params));
+ //
+ // {
+ // "time":1588778516608,
+ // "marketId":250,
+ // "price":0.0,
+ // "change":0.0,
+ // "volumeBase":0.0,
+ // "volume":0.0,
+ // "low":0.0,
+ // "high":0.0,
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ parseTickers (tickers, symbols = undefined) {
+ const result = [];
+ for (let i = 0; i < tickers.length; i++) {
+ result.push (this.parseTicker (tickers[i]));
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'quote': 'USDT', // identifier of a quote asset to filter the markets
+ };
+ const response = await this.publicGetTickers (this.extend (request, params));
+ //
+ // [
+ // {
+ // "time":1588831771698,
+ // "marketId":33,
+ // "price":204.54,
+ // "change":-1.03,
+ // "volumeBase":544.9801776699998,
+ // "volume":111550.433735,
+ // "low":200.33,
+ // "high":209.51
+ // },
+ // ]
+ //
+ return this.parseTickers (response, symbols);
+ }
+
+ parseTrade (trade, market) {
+ //
+ // fetchTrades (public)
+ //
+ // {
+ // "id":251199246,
+ // "side":2,
+ // "price":0.022044,
+ // "executedAt":1588830682664,
+ // "qty":0.13545846,
+ // "makerId":"67ed6ef3-33d8-4389-ba70-5c68d9db9f6c",
+ // "takerId":"229ef0d6-fe67-4b5d-9733-824142fab8f3"
+ // }
+ //
+ // fetchMyTrades, fetchOrderTrades (private)
+ //
+ // {
+ // "id": 123,
+ // "marketId": 123,
+ // "side": 1,
+ // "qty": "1.23456",
+ // "price": "1.23456",
+ // "cost": "1.23456",
+ // "fee": "1.23456",
+ // "feeAsset": "XBASE",
+ // "liquidity": 1,
+ // "orderId": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "tradeId": 123,
+ // "filledAt": 1556355722341
+ // }
+ //
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'qty');
+ let fee = undefined;
+ const feeCost = this.safeFloat (trade, 'fee');
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (trade, 'feeAsset');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ let cost = this.safeFloat (trade, 'qty');
+ if ((cost === undefined) && (price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ const timestamp = this.safeInteger2 (trade, 'executedAt', 'filledAt');
+ const tradeSide = this.safeString (trade, 'side');
+ const side = (tradeSide === '1') ? 'buy' : 'sell';
+ const liquidity = this.safeString (trade, 'liquidity');
+ let takerOrMaker = undefined;
+ if (liquidity !== undefined) {
+ takerOrMaker = (liquidity === '1') ? 'maker' : 'taker';
+ }
+ const orderId = this.safeString (trade, 'orderId');
+ const id = this.safeString (trade, 'id');
+ const marketId = this.safeString (trade, 'marketId');
+ const symbol = this.safeSymbol (marketId, market);
+ return {
+ 'info': trade,
+ 'id': id,
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'order': orderId,
+ 'type': undefined,
+ 'side': side,
+ 'takerOrMaker': takerOrMaker,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'id': market['id'],
+ // 'offset': 0 // the number of records to skip
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.publicGetMarketsIdTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id":251199246,
+ // "side":2,
+ // "price":0.022044,
+ // "executedAt":1588830682664,
+ // "qty":0.13545846,
+ // "makerId":"67ed6ef3-33d8-4389-ba70-5c68d9db9f6c",
+ // "takerId":"229ef0d6-fe67-4b5d-9733-824142fab8f3"
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': this.marketId (symbol),
+ };
+ const response = await this.marketsGetIdOrderBook (this.extend (request, params));
+ //
+ // {
+ // "type":"ob_snapshot",
+ // "marketId":3,
+ // "timestamp":1588836429847,
+ // "bids":[
+ // [0.021694,8.8793688,1], // price, amount, count
+ // [0.01937,7.1340473,1],
+ // [0.020774,3.314881,1],
+ // ],
+ // "asks":[
+ // [0.02305,8.8793688,1],
+ // [0.028022,3.314881,1],
+ // [0.022598,3.314881,1],
+ // ]
+ // }
+ //
+ const timestamp = this.safeInteger (response, 'timestamp');
+ return this.parseOrderBook (response, timestamp);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "time":1588807500000,
+ // "open":0.022077,
+ // "high":0.022077,
+ // "low":0.022051,
+ // "close":0.022051,
+ // "volume":10.532025119999997
+ // }
+ //
+ return [
+ this.safeInteger (ohlcv, 'time'),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'volume'),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ const request = {
+ // 'id': market['id'],
+ 'interval': this.timeframes[timeframe],
+ // 'start': 1588830682664, // milliseconds
+ // 'end': 1588830682664, // milliseconds
+ };
+ const duration = this.parseTimeframe (timeframe);
+ const now = this.milliseconds ();
+ if (since !== undefined) {
+ request['start'] = since;
+ if (limit === undefined) {
+ request['end'] = now;
+ } else {
+ request['end'] = this.sum (since, duration * limit * 1000);
+ }
+ } else if (limit !== undefined) {
+ request['start'] = now - duration * limit * 1000;
+ request['end'] = now;
+ } else {
+ throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument, or a limit argument, or both');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ request['id'] = market['id'];
+ const response = await this.publicGetMarketsIdOhlcv (this.extend (request, params));
+ //
+ // [
+ // {"time":1588807500000,"open":0.022077,"high":0.022077,"low":0.022051,"close":0.022051,"volume":10.532025119999997},
+ // {"time":1588807800000,"open":0.022051,"high":0.022051,"low":0.022044,"close":0.022044,"volume":0.655987},
+ // {"time":1588808400000,"open":0.022044,"high":0.022044,"low":0.022044,"close":0.022044,"volume":3.9615545499999993},
+ // ]
+ //
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': this.uid,
+ };
+ const response = await this.privateGetAccountsIdBalances (this.extend (request, params));
+ //
+ // [
+ // {
+ // "assetId":"USDT",
+ // "available":"25",
+ // "balance":"25",
+ // "reserved":"0",
+ // "balanceBtc":"0.0",
+ // "balanceRef":"0.0",
+ // }
+ // ]
+ //
+ const result = { 'info': response };
+ for (let i = 0; i < response.length; i++) {
+ const balance = response[i];
+ const currencyId = this.safeString (balance, 'assetId');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = {
+ 'free': this.safeFloat (balance, 'available'),
+ 'used': this.safeFloat (balance, 'reserved'),
+ 'total': this.safeFloat (balance, 'balance'),
+ };
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const response = await this.privateGetOrdersId (this.extend (request, params));
+ //
+ // {
+ // "id": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "accountId": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "marketId": 123,
+ // "type": 1,
+ // "side": 1,
+ // "qty": "1.23456",
+ // "cost": "1.23456",
+ // "remainingQty": "1.23456",
+ // "remainingCost": "1.23456",
+ // "limitPrice": "1.23456",
+ // "stopPrice": "1.23456",
+ // "postOnly": false,
+ // "timeInForce": "GTC",
+ // "state": 1,
+ // "closeReason": "FILLED",
+ // "placedAt": 1556355722341,
+ // "closedAt": 1556355722341
+ // }
+ //
+ return this.parseOrder (response);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ '1': undefined, // pending
+ '2': 'open', // open
+ '3': 'open', // partially filled
+ '4': 'closed', // closed
+ 'FILLED': 'closed',
+ 'USER_REQUESTED_CANCEL': 'canceled',
+ 'ADMINISTRATIVE_CANCEL': 'canceled',
+ 'NOT_ENOUGH_LIQUIDITY': 'canceled',
+ 'EXPIRED': 'expired',
+ 'ONE_CANCELS_OTHER': 'canceled',
+ };
+ return this.safeString (statuses, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // fetchOrder, fetchOpenOrders, fetchClosedOrders
+ //
+ // {
+ // "id": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "accountId": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "marketId": 123,
+ // "type": 1,
+ // "side": 1,
+ // "qty": "1.23456",
+ // "cost": "1.23456",
+ // "remainingQty": "1.23456",
+ // "remainingCost": "1.23456",
+ // "limitPrice": "1.23456",
+ // "stopPrice": "1.23456",
+ // "postOnly": false,
+ // "timeInForce": "GTC",
+ // "state": 1,
+ // "closeReason": "FILLED",
+ // "placedAt": 1556355722341,
+ // "closedAt": 1556355722341
+ // }
+ //
+ // createOrder
+ //
+ // market buy
+ //
+ // {
+ // "id":"ff81127c-8fd5-4846-b683-110639dcd322",
+ // "accountId":"6d445378-d8a3-4932-91cd-545d0a4ad2a2",
+ // "marketId":33,
+ // "type":1,
+ // "side":1,
+ // "cost":"25",
+ // "postOnly":false,
+ // "timeInForce":"GTC",
+ // "state":1,
+ // "placedAt":1589510846735
+ // }
+ //
+ // market sell, limit buy, limit sell
+ //
+ // {
+ // "id":"042a38b0-e369-4ad2-ae73-a18ff6b1dcf1",
+ // "accountId":"6d445378-d8a3-4932-91cd-545d0a4ad2a2",
+ // "marketId":33,
+ // "type":2,
+ // "side":1,
+ // "qty":"1000",
+ // "limitPrice":"100",
+ // "postOnly":false,
+ // "timeInForce":"GTC",
+ // "state":1,
+ // "placedAt":1589403938682,
+ // }
+ //
+ const id = this.safeString (order, 'id');
+ const timestamp = this.safeInteger (order, 'placedAt');
+ const marketId = this.safeInteger (order, 'marketId');
+ const symbol = this.safeSymbol (marketId, market);
+ let status = this.parseOrderStatus (this.safeString (order, 'state'));
+ if (status === 'closed') {
+ status = this.parseOrderStatus (this.safeString (order, 'closeReason'));
+ }
+ const orderSide = this.safeString (order, 'side');
+ const side = (orderSide === '1') ? 'buy' : 'sell';
+ const orderType = this.safeString (order, 'type');
+ let type = undefined;
+ if (orderType === '1') {
+ type = 'market';
+ } else if (orderType === '2') {
+ type = 'limit';
+ } else if (orderType === '3') {
+ type = 'stopmarket';
+ } else {
+ type = 'stoplimit';
+ }
+ let price = this.safeFloat (order, 'limitPrice');
+ const amount = this.safeFloat (order, 'qty');
+ let remaining = this.safeFloat (order, 'remainingQty');
+ let filled = undefined;
+ const remainingCost = this.safeFloat (order, 'remainingCost');
+ if ((remainingCost !== undefined) && (remainingCost === 0.0)) {
+ remaining = 0;
+ }
+ if ((amount !== undefined) && (remaining !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ const cost = this.safeFloat (order, 'cost');
+ if (type === 'market') {
+ if (price === 0.0) {
+ if ((cost !== undefined) && (filled !== undefined)) {
+ if ((cost > 0) && (filled > 0)) {
+ price = cost / filled;
+ }
+ }
+ }
+ }
+ let average = undefined;
+ if (cost !== undefined) {
+ if (filled) {
+ average = cost / filled;
+ }
+ }
+ const timeInForce = this.safeString (order, 'timeInForce');
+ const stopPrice = this.safeFloat (order, 'stopPrice');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'side': side,
+ 'timeInForce': timeInForce,
+ 'price': price,
+ 'stopPrice': stopPrice,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': undefined,
+ 'trades': undefined,
+ };
+ }
+
+ async fetchOrdersByState (state, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const now = this.milliseconds ();
+ const ninetyDays = 90 * 24 * 60 * 60 * 1000; // 90 days timerange max
+ const request = {
+ 'id': this.uid,
+ 'state': state,
+ // 'side': Integer, // 1 = buy, 2 = sell
+ // 'offset': 0, // the number of records to skip
+ };
+ if (since === undefined) {
+ request['from'] = now - ninetyDays;
+ request['to'] = now;
+ } else {
+ request['from'] = since;
+ request['to'] = this.sum (since, ninetyDays);
+ }
+ await this.loadMarkets ();
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['marketId'] = market['id'];
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 50
+ }
+ const response = await this.privateGetAccountsIdOrders (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "accountId": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "marketId": 123,
+ // "type": 1,
+ // "side": 1,
+ // "qty": "1.23456",
+ // "cost": "1.23456",
+ // "remainingQty": "1.23456",
+ // "remainingCost": "1.23456",
+ // "limitPrice": "1.23456",
+ // "stopPrice": "1.23456",
+ // "postOnly": false,
+ // "timeInForce": "GTC",
+ // "state": 1,
+ // "closeReason": "FILLED",
+ // "placedAt": 1556355722341,
+ // "closedAt": 1556355722341
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchOrdersByState ('INACTIVE', symbol, since, limit, params);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchOrdersByState ('ACTIVE', symbol, since, limit, params);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const now = this.milliseconds ();
+ const ninetyDays = 90 * 24 * 60 * 60 * 1000; // 90 days timerange max
+ const request = {
+ 'id': this.uid,
+ // 'side': Integer, // 1 = buy, 2 = sell
+ // 'offset': 0, // the number of records to skip
+ };
+ if (since === undefined) {
+ request['from'] = now - ninetyDays;
+ request['to'] = now;
+ } else {
+ request['from'] = since;
+ request['to'] = this.sum (since, ninetyDays);
+ }
+ await this.loadMarkets ();
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['marketId'] = market['id'];
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 50, max 200
+ }
+ const response = await this.privateGetAccountsIdFills (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id": 123,
+ // "marketId": 123,
+ // "side": 1,
+ // "qty": "1.23456",
+ // "price": "1.23456",
+ // "cost": "1.23456",
+ // "fee": "1.23456",
+ // "feeAsset": "XBASE",
+ // "liquidity": 1,
+ // "orderId": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "tradeId": 123,
+ // "filledAt": 1556355722341
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const trades = await this.privateGetOrdersIdFills (this.extend (request, params));
+ return this.parseTrades (trades);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const uppercaseType = type.toUpperCase ();
+ if (uppercaseType === 'MARKET') {
+ type = 1;
+ } else if (uppercaseType === 'LIMIT') {
+ type = 2;
+ } else if (uppercaseType === 'STOPMARKET') {
+ type = 3;
+ } else if (uppercaseType === 'STOPLIMIT') {
+ type = 4;
+ }
+ const uppercaseSide = side.toUpperCase ();
+ side = uppercaseSide === 'BUY' ? 1 : 2;
+ const request = {
+ 'accountId': this.uid,
+ 'marketId': market['id'],
+ 'type': type,
+ 'side': side,
+ // 'postOnly': false,
+ // 'timeInForce': 'GTC',
+ };
+ const clientOrderId = this.safeValue2 (params, 'refId', 'clientOrderId');
+ let query = params;
+ if (clientOrderId !== undefined) {
+ request['refId'] = clientOrderId;
+ query = this.omit (params, [ 'refId', 'clientOrderId' ]);
+ }
+ if ((uppercaseType === 'MARKET') && (uppercaseSide === 'BUY')) {
+ // for market buy it requires the amount of quote currency to spend
+ let cost = this.safeFloat (params, 'cost');
+ if (this.options['createMarketBuyOrderRequiresPrice']) {
+ if (cost === undefined) {
+ if (price !== undefined) {
+ cost = amount * price;
+ } else {
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false to supply the cost in the amount argument (the exchange-specific behaviour)");
+ }
+ }
+ } else {
+ cost = (cost === undefined) ? amount : cost;
+ }
+ const precision = market['precision']['price'];
+ request['cost'] = this.decimalToPrecision (cost, TRUNCATE, precision, this.precisionMode);
+ } else {
+ request['qty'] = this.amountToPrecision (symbol, amount);
+ }
+ if (uppercaseType === 'LIMIT') {
+ request['limitPrice'] = this.priceToPrecision (symbol, price);
+ }
+ const response = await this.privatePostOrders (this.extend (request, query));
+ //
+ // market buy
+ //
+ // {
+ // "id":"ff81127c-8fd5-4846-b683-110639dcd322",
+ // "accountId":"6d445378-d8a3-4932-91cd-545d0a4ad2a2",
+ // "marketId":33,
+ // "type":1,
+ // "side":1,
+ // "cost":"25",
+ // "postOnly":false,
+ // "timeInForce":"GTC",
+ // "state":1,
+ // "placedAt":1589510846735
+ // }
+ //
+ // market sell, limit buy, limit sell
+ //
+ // {
+ // "id":"042a38b0-e369-4ad2-ae73-a18ff6b1dcf1",
+ // "accountId":"6d445378-d8a3-4932-91cd-545d0a4ad2a2",
+ // "marketId":33,
+ // "type":2,
+ // "side":1,
+ // "qty":"1000",
+ // "limitPrice":"100",
+ // "postOnly":false,
+ // "timeInForce":"GTC",
+ // "state":1,
+ // "placedAt":1589403938682,
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ const request = {
+ 'id': id,
+ };
+ return await this.privateDeleteOrdersId (this.extend (request, params));
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'id': this.uid,
+ 'accountId': this.uid,
+ 'assetId': currency['id'],
+ 'amount': amount,
+ // 'cryptoAddress': address,
+ // 'accountNumber': 'IBAN', // IBAN account number
+ // 'networkId': 'XBASE', // underlying network
+ };
+ if (address !== undefined) {
+ request['cryptoAddress'] = address;
+ if (tag !== undefined) {
+ request['memo'] = tag;
+ }
+ }
+ const response = await this.privatePostAccountsIdWithdrawals (this.extend (request, params));
+ //
+ // {
+ // "id": "98b62dde-a87f-45f0-8db8-80ae2d312fa6"
+ // }
+ //
+ return {
+ 'info': response,
+ 'id': this.safeString (response, 'id'),
+ };
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, httpHeaders = undefined, body = undefined) {
+ const query = this.omit (params, this.extractParams (path));
+ let request = '/';
+ if (api === 'public') {
+ request += 'api/' + this.version;
+ } else if (api === 'private') {
+ request += 'api/' + this.version;
+ } else if (api === 'markets') {
+ request += 'api/' + api;
+ }
+ request += '/' + this.implodeParams (path, params);
+ if (method === 'GET') {
+ if (Object.keys (query).length) {
+ request += '?' + this.urlencode (query);
+ }
+ }
+ const url = this.urls['api'] + request;
+ if (api === 'private') {
+ this.checkRequiredCredentials ();
+ let payload = '';
+ if (method !== 'GET') {
+ if (Object.keys (query).length) {
+ body = this.json (query);
+ payload = body;
+ }
+ }
+ // construct signature
+ const hasBody = (method === 'POST') || (method === 'PUT') || (method === 'PATCH');
+ // const date = 'Mon, 30 Sep 2019 13:57:23 GMT';
+ const date = this.rfc2616 (this.milliseconds ());
+ let headersCSV = 'date' + ' ' + 'request-line';
+ let message = 'date' + ':' + ' ' + date + "\n" + method + ' ' + request + ' HTTP/1.1'; // eslint-disable-line quotes
+ let digest = '';
+ if (hasBody) {
+ digest = 'SHA-256=' + this.hash (payload, 'sha256', 'base64');
+ message += "\ndigest" + ':' + ' ' + digest; // eslint-disable-line quotes
+ headersCSV += ' ' + 'digest';
+ }
+ const signature = this.hmac (this.encode (message), this.encode (this.secret), 'sha256', 'base64');
+ const authorizationHeader = 'hmac username="' + this.apiKey + '",algorithm="hmac-sha256",headers="' + headersCSV + '",' + 'signature="' + signature + '"';
+ httpHeaders = {
+ 'Date': date,
+ 'Authorization': authorizationHeader,
+ 'Content-Type': 'application/json',
+ };
+ if (hasBody) {
+ httpHeaders['Digest'] = digest;
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': httpHeaders };
+ }
+
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ //
+ // {"message":"Invalid cost","_links":{"self":{"href":"/orders","templated":false}}}
+ //
+ const message = this.safeString (response, 'message');
+ if (message !== undefined) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],79:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -50710,23 +62060,28 @@ module.exports = class exmo extends Exchange {
'rateLimit': 350, // once every 350 ms ≈ 180 requests per minute ≈ 3 requests per second
'version': 'v1.1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchClosedOrders': 'emulated',
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': true,
'fetchDepositAddress': true,
+ 'fetchFundingFees': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': 'emulated',
- 'fetchOrders': 'emulated',
- 'fetchOrderTrades': true,
+ 'fetchOrderBook': true,
'fetchOrderBooks': true,
- 'fetchMyTrades': true,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
'fetchTickers': true,
- 'withdraw': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
- 'fetchFundingFees': true,
- 'fetchCurrencies': true,
'fetchTransactions': true,
- 'fetchOHLCV': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1',
@@ -50767,11 +62122,14 @@ module.exports = class exmo extends Exchange {
'public': {
'get': [
'currency',
+ 'currency/list/extended',
'order_book',
'pair_settings',
'ticker',
'trades',
'candles_history',
+ 'required_amount',
+ 'payments/providers/crypto/list',
],
},
'private': {
@@ -50785,13 +62143,14 @@ module.exports = class exmo extends Exchange {
'user_trades',
'user_cancelled_orders',
'order_trades',
- 'required_amount',
'deposit_address',
'withdraw_crypt',
'withdraw_get_txid',
'excode_create',
'excode_load',
+ 'code_check',
'wallet_history',
+ 'wallet_operations',
],
},
},
@@ -50815,229 +62174,210 @@ module.exports = class exmo extends Exchange {
'error': '',
'data': {
'limits': [
- { 'pair': 'ALGO/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' },
- { 'pair': 'ALGO/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '50' },
- { 'pair': 'ATOM/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '50000000' },
- { 'pair': 'ATOM/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'BTC/USD', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'BTC/RUB', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'BTC/EUR', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'BTC/UAH', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '15000000', 'min_a': '10', 'max_a': '15000000' },
- { 'pair': 'BTC/GBP', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'ETH/GBP', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'XRP/GBP', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
- { 'pair': 'USDT/GBP', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'BTC/PLN', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '20000000', 'min_a': '50', 'max_a': '2000000' },
- { 'pair': 'BTC/TRY', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000' },
- { 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000' },
- { 'pair': 'BTC/USDT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'ETH/BTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ETH/USD', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'ETH/RUB', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
- { 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
- { 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000' },
- { 'pair': 'ADA/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' },
- { 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'ALGO/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'ALGO/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' },
- { 'pair': 'ALGO/EUR', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'ATOM/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'ATOM/EUR', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' },
- { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' },
- { 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' },
- { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' },
- { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'BTCZ/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000' },
- { 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' },
- { 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' },
- { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' },
- { 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
- { 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
- { 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000' },
- { 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000' },
- { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
- { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' },
- { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000' },
- { 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000' },
- { 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '50000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' },
- { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ETH/EUR', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'ETH/UAH', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000' },
- { 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '2000000' },
- { 'pair': 'ETH/TRY', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000' },
- { 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'ETH/USDT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'ETH/LTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '100000', 'min_a': '0.05', 'max_a': '100000' },
- { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' },
- { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' },
- { 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
- { 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' },
- { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'GNT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
- { 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'GUSD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'GUSD/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' },
- { 'pair': 'HP/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'HB/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' },
- { 'pair': 'INK/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'INK/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'INK/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' },
- { 'pair': 'KICK/RUB', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'KICK/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
- { 'pair': 'KICK/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'KICK/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' },
- { 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' },
- { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' },
- { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
- { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000' },
- { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'MKR/BTC', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100' },
- { 'pair': 'MKR/DAI', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000' },
- { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' },
- { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' },
- { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' },
- { 'pair': 'MNX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'MNX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'MNX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
- { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' },
- { 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
- { 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000' },
- { 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
- { 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000' },
- { 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000' },
- { 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000' },
- { 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
- { 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000' },
- { 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000' },
- { 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000' },
- { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' },
- { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' },
- { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' },
- { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' },
- { 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'TRX/EUR', 'min_q': '0.01', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
- { 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
- { 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000' },
- { 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' },
- { 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' },
- { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' },
- { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' },
- { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' },
- { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
- { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' },
- { 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000' },
- { 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000' },
- { 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' },
- { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
- { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' },
- { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' },
- { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
- { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' },
- { 'pair': 'XTZ/USD', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000' },
- { 'pair': 'XTZ/RUB', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'XTZ/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
- { 'pair': 'XTZ/ETH', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '1000' },
- { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
- { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'ZRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
- { 'pair': 'ZAG/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'USD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'EXM/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0000001', 'max_a': '1' },
- { 'pair': 'ATMCASH/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' },
+ { 'pair': 'BTC/USD', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/RUB', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/EUR', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/GBP', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/UAH', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '15000000', 'min_a': '10', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/PLN', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '20000000', 'min_a': '50', 'max_a': '2000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/TRY', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/USDT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'ETH/BTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/USD', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/RUB', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ADA/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ALGO/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ALGO/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '50', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ALGO/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'ALGO/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ALGO/EUR', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ATOM/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ATOM/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ATOM/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ATOM/EUR', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/EUR', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/GBP', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/UAH', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '2000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/TRY', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/USDT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'ETH/LTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '100000', 'min_a': '0.05', 'max_a': '100000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GNT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GUSD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GUSD/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'HP/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'HB/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'MKR/BTC', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'MKR/DAI', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'TRX/EUR', 'min_q': '0.01', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDT/GBP', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/GBP', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XTZ/USD', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XTZ/RUB', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XTZ/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XTZ/ETH', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '1000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZAG/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'EXM/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0000001', 'max_a': '1', 'taker': '0.4', 'maker': '0.4' },
],
'fees': [
{
'group': 'crypto',
- 'title': 'Криптовалюта',
+ 'title': 'Cryptocurrency',
'items': [
{ 'prov': 'EXM', 'dep': '0%', 'wd': '1 EXM' },
- { 'prov': 'BTC', 'dep': '0%', 'wd': '0.0005 BTC' },
+ { 'prov': 'BTC', 'dep': '0%', 'wd': '0.0004 BTC' },
{ 'prov': 'LTC', 'dep': '0%', 'wd': '0.01 LTC' },
- { 'prov': 'DOGE', 'dep': '0%', 'wd': '1 DOGE' },
- { 'prov': 'DASH', 'dep': '0%', 'wd': '0.01 DASH' },
- { 'prov': 'ETH', 'dep': '0%', 'wd': '0.01 ETH' },
+ { 'prov': 'DOGE', 'dep': '0%', 'wd': '1 Doge' },
+ { 'prov': 'DASH', 'dep': '0%', 'wd': '0.002 DASH' },
+ { 'prov': 'ETH', 'dep': '0%', 'wd': '0.003 ETH' },
{ 'prov': 'WAVES', 'dep': '0%', 'wd': '0.001 WAVES' },
{ 'prov': 'ZEC', 'dep': '0%', 'wd': '0.001 ZEC' },
- { 'prov': 'USDT', 'dep': '0%', 'wd': '5 USDT' },
- { 'prov': 'XMR', 'dep': '0%', 'wd': '0.05 XMR' },
+ { 'prov': 'USDT', 'dep': '0%', 'wd': '' },
+ { 'prov': 'XMR', 'dep': '0%', 'wd': '0.001 XMR' },
{ 'prov': 'XRP', 'dep': '0%', 'wd': '0.02 XRP' },
- { 'prov': 'KICK', 'dep': '0%', 'wd': '50 KICK' },
{ 'prov': 'ETC', 'dep': '0%', 'wd': '0.01 ETC' },
{ 'prov': 'BCH', 'dep': '0%', 'wd': '0.001 BCH' },
{ 'prov': 'BTG', 'dep': '0%', 'wd': '0.001 BTG' },
{ 'prov': 'EOS', 'dep': '0%', 'wd': '0.05 EOS' },
- { 'prov': 'BTCZ', 'dep': '0%', 'wd': '5 BTCZ' },
- { 'prov': 'DXT', 'dep': '20 DXT', 'wd': '20 DXT' },
{ 'prov': 'XLM', 'dep': '0%', 'wd': '0.01 XLM' },
- { 'prov': 'MNX', 'dep': '0%', 'wd': '0.01 MNX' },
{ 'prov': 'OMG', 'dep': '0.1 OMG', 'wd': '0.5 OMG' },
{ 'prov': 'TRX', 'dep': '0%', 'wd': '1 TRX' },
{ 'prov': 'ADA', 'dep': '0%', 'wd': '1 ADA' },
- { 'prov': 'INK', 'dep': '10 INK', 'wd': '50 INK' },
{ 'prov': 'NEO', 'dep': '0%', 'wd': '0%' },
{ 'prov': 'GAS', 'dep': '0%', 'wd': '0%' },
{ 'prov': 'ZRX', 'dep': '0%', 'wd': '1 ZRX' },
@@ -51051,29 +62391,28 @@ module.exports = class exmo extends Exchange {
{ 'prov': 'DAI', 'dep': '0%', 'wd': '1 DAI' },
{ 'prov': 'MKR', 'dep': '0%', 'wd': '0.005 MKR' },
{ 'prov': 'MNC', 'dep': '0%', 'wd': '15 MNC' },
- { 'prov': 'PTI', 'dep': '0%', 'wd': '10 PTI' },
- { 'prov': 'ATMCASH', 'dep': '0%', 'wd': '5 ATMCASH' },
+ { 'prov': 'PTI', 'dep': '-', 'wd': '10 PTI' },
{ 'prov': 'ETZ', 'dep': '0%', 'wd': '1 ETZ' },
{ 'prov': 'USDC', 'dep': '0%', 'wd': '0.5 USDC' },
{ 'prov': 'ROOBEE', 'dep': '0%', 'wd': '200 ROOBEE' },
{ 'prov': 'DCR', 'dep': '0%', 'wd': '0.01 DCR' },
{ 'prov': 'ZAG', 'dep': '0%', 'wd': '0%' },
- { 'prov': 'BTT', 'dep': '0%', 'wd': '100 BTT' },
+ { 'prov': 'BTT', 'dep': '0 BTT', 'wd': '100 BTT' },
{ 'prov': 'VLX', 'dep': '0%', 'wd': '1 VLX' },
{ 'prov': 'CRON', 'dep': '0%', 'wd': '5 CRON' },
{ 'prov': 'ONT', 'dep': '0%', 'wd': '1 ONT' },
{ 'prov': 'ONG', 'dep': '0%', 'wd': '5 ONG' },
{ 'prov': 'ALGO', 'dep': '0%', 'wd': '0.01 ALGO' },
- { 'prov': 'ATOM', 'dep': '0%', 'wd': '' },
+ { 'prov': 'ATOM', 'dep': '0%', 'wd': '0.05 ATOM' },
],
},
{
'group': 'usd',
'title': 'USD',
'items': [
- { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' },
- { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.49%' },
+ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
+ { 'prov': 'AdvCash', 'dep': '0%', 'wd': '2.49%' },
{ 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 USD', 'wd': '-' },
{ 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' },
{ 'prov': 'Frick Bank', 'dep': '0 USD', 'wd': '-' },
@@ -51083,24 +62422,32 @@ module.exports = class exmo extends Exchange {
'group': 'eur',
'title': 'EUR',
'items': [
+ { 'prov': 'Visa/MasterCard', 'dep': '4.5% + 0.5 EUR', 'wd': '-' },
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
- { 'prov': 'Visa/MasterCard', 'dep': '4.5% + 0.5 EUR', 'wd': '-' },
{ 'prov': 'Visa', 'dep': '2.95%', 'wd': '-' },
{ 'prov': 'Frick Internal Transfer', 'dep': '0 EUR', 'wd': '-' },
- { 'prov': 'SEPA Frick Bank', 'dep': '0 EUR', 'wd': '-' },
- { 'prov': 'WIRE Frick Bank', 'dep': '0%', 'wd': '-' },
+ { 'prov': 'SEPA Frick Bank', 'dep': '0 EUR', 'wd': '1 EUR' },
+ { 'prov': 'WIRE Frick Bank', 'dep': '0%', 'wd': '20 EUR' },
{ 'prov': 'SEPA Weg Ag', 'dep': '-', 'wd': '1 EUR' },
],
},
+ {
+ 'group': 'gbp',
+ 'title': 'GBP',
+ 'items': [
+ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
+ { 'prov': 'WIRE Frick Bank', 'dep': '10 GBP', 'wd': '-' },
+ ],
+ },
{
'group': 'rub',
'title': 'RUB',
'items': [
- { 'prov': 'Payeer', 'dep': '2.49%', 'wd': '3.99%' },
+ { 'prov': 'Payeer', 'dep': '2.49%', 'wd': '3.49%' },
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Qiwi', 'dep': '1.49%', 'wd': '2.49%' },
- { 'prov': 'Yandex Money', 'dep': '1.49%', 'wd': '-' },
- { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.49%' },
+ { 'prov': 'Yandex Money', 'dep': '1.49%', 'wd': '1.95 %' },
+ { 'prov': 'AdvCash', 'dep': '0.99%', 'wd': '0.99%' },
{ 'prov': 'Visa/MasterCard', 'dep': '2.99%', 'wd': '3.99% + 60 RUB' },
],
},
@@ -51127,17 +62474,16 @@ module.exports = class exmo extends Exchange {
'items': [
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Terminal', 'dep': '2.6%', 'wd': '-' },
- { 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '-' },
{ 'prov': 'Visa/MasterCard EasyTransfer', 'dep': '-', 'wd': '2.99%' },
+ { 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '-' },
],
},
{
'group': 'kzt',
'title': 'KZT',
'items': [
+ { 'prov': 'Visa/MasterCard', 'dep': '3.5%', 'wd': '2.99% + 450 KZT' },
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
- { 'prov': 'Visa/MasterCard RoyalPay', 'dep': '-', 'wd': '2.99% + 450 KZT' },
- { 'prov': 'Visa/MasterCard', 'dep': '3.5%', 'wd': '-' },
{ 'prov': 'AdvCash', 'dep': '0%', 'wd': '-' },
],
},
@@ -51158,6 +62504,7 @@ module.exports = class exmo extends Exchange {
'50054': InsufficientFunds,
'50304': OrderNotFound, // "Order was not found '123456789'" (fetching order trades for an order that does not have trades yet)
'50173': OrderNotFound, // "Order with id X was not found." (cancelling non-existent, closed and cancelled order)
+ '50277': InvalidOrder,
'50319': InvalidOrder, // Price by order is less than permissible minimum for this pair
'50321': InvalidOrder, // Price by order is more than permissible maximum for this pair
},
@@ -51167,6 +62514,7 @@ module.exports = class exmo extends Exchange {
'API rate limit exceeded': RateLimitExceeded, // {"result":false,"error":"API rate limit exceeded for 99.33.55.224. Retry after 60 sec.","history":[],"begin":1579392000,"end":1579478400}
},
},
+ 'orders': {}, // orders cache / emulation
});
}
@@ -51204,6 +62552,9 @@ module.exports = class exmo extends Exchange {
if ((input === undefined) || (input === '-')) {
return undefined;
}
+ if (input === '') {
+ return 0;
+ }
const isPercentage = (input.indexOf ('%') >= 0);
const parts = input.split (' ');
const value = parts[0].replace ('%', '');
@@ -51233,14 +62584,10 @@ module.exports = class exmo extends Exchange {
const withdrawalFee = this.safeString (item, 'wd');
const depositFee = this.safeString (item, 'dep');
if (withdrawalFee !== undefined) {
- if (withdrawalFee.length > 0) {
- withdraw[code] = this.parseFixedFloatValue (withdrawalFee);
- }
+ withdraw[code] = this.parseFixedFloatValue (withdrawalFee);
}
if (depositFee !== undefined) {
- if (depositFee.length > 0) {
- deposit[code] = this.parseFixedFloatValue (depositFee);
- }
+ deposit[code] = this.parseFixedFloatValue (depositFee);
}
}
// sets fiat fees to undefined
@@ -51328,15 +62675,16 @@ module.exports = class exmo extends Exchange {
const response = await this.publicGetPairSettings (params);
//
// {
- // "EXM_ETH": {
- // "min_quantity": "1",
- // "max_quantity": "1000",
- // "min_price": "1",
- // "max_price": "1000",
- // "max_amount": "1000",
- // "min_amount": "1",
- // "commission_taker_percent": "0.2",
- // "commission_maker_percent": "0.2"
+ // "BTC_USD":{
+ // "min_quantity":"0.0001",
+ // "max_quantity":"1000",
+ // "min_price":"1",
+ // "max_price":"30000",
+ // "max_amount":"500000",
+ // "min_amount":"1",
+ // "price_precision":8,
+ // "commission_taker_percent":"0.4",
+ // "commission_maker_percent":"0.4"
// },
// }
//
@@ -51377,7 +62725,7 @@ module.exports = class exmo extends Exchange {
},
'precision': {
'amount': 8,
- 'price': 8,
+ 'price': this.safeInteger (market, 'price_precision'),
},
'info': market,
});
@@ -51432,7 +62780,7 @@ module.exports = class exmo extends Exchange {
return this.parseOHLCVs (candles, market, timeframe, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// "t":1584057600000,
@@ -51457,16 +62805,18 @@ module.exports = class exmo extends Exchange {
await this.loadMarkets ();
const response = await this.privatePostUserInfo (params);
const result = { 'info': response };
- const codes = Object.keys (this.currencies);
+ const free = this.safeValue (response, 'balances', {});
+ const used = this.safeValue (response, 'reserved', {});
+ const codes = Object.keys (free);
for (let i = 0; i < codes.length; i++) {
const code = codes[i];
const currencyId = this.currencyId (code);
const account = this.account ();
- if (currencyId in response['balances']) {
- account['free'] = this.safeFloat (response['balances'], currencyId);
+ if (currencyId in free) {
+ account['free'] = this.safeFloat (free, currencyId);
}
- if (currencyId in response['reserved']) {
- account['used'] = this.safeFloat (response['reserved'], currencyId);
+ if (currencyId in used) {
+ account['used'] = this.safeFloat (used, currencyId);
}
result[code] = account;
}
@@ -51565,7 +62915,7 @@ module.exports = class exmo extends Exchange {
const ticker = response[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -51762,7 +63112,7 @@ module.exports = class exmo extends Exchange {
amount = parseFloat (amount);
price = parseFloat (price);
const status = 'open';
- const order = {
+ return {
'id': id,
'info': response,
'timestamp': timestamp,
@@ -51782,60 +63132,45 @@ module.exports = class exmo extends Exchange {
'clientOrderId': undefined,
'average': undefined,
};
- this.orders[id] = order;
- return order;
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const request = { 'order_id': id };
- const response = await this.privatePostOrderCancel (this.extend (request, params));
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- }
- return response;
+ return await this.privatePostOrderCancel (this.extend (request, params));
}
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- try {
- const request = {
- 'order_id': id.toString (),
- };
- const response = await this.privatePostOrderTrades (this.extend (request, params));
- //
- // {
- // "type": "buy",
- // "in_currency": "BTC",
- // "in_amount": "1",
- // "out_currency": "USD",
- // "out_amount": "100",
- // "trades": [
- // {
- // "trade_id": 3,
- // "date": 1435488248,
- // "type": "buy",
- // "pair": "BTC_USD",
- // "order_id": 12345,
- // "quantity": 1,
- // "price": 100,
- // "amount": 100
- // }
- // ]
- // }
- //
- const order = this.parseOrder (response);
- return this.extend (order, {
- 'id': id.toString (),
- });
- } catch (e) {
- if (e instanceof OrderNotFound) {
- if (id in this.orders) {
- return this.orders[id];
- }
- }
- }
- throw new OrderNotFound (this.id + ' fetchOrder order id ' + id.toString () + ' not found in cache.');
+ const request = {
+ 'order_id': id.toString (),
+ };
+ const response = await this.privatePostOrderTrades (this.extend (request, params));
+ //
+ // {
+ // "type": "buy",
+ // "in_currency": "BTC",
+ // "in_amount": "1",
+ // "out_currency": "USD",
+ // "out_amount": "100",
+ // "trades": [
+ // {
+ // "trade_id": 3,
+ // "date": 1435488248,
+ // "type": "buy",
+ // "pair": "BTC_USD",
+ // "order_id": 12345,
+ // "quantity": 1,
+ // "price": 100,
+ // "amount": 100
+ // }
+ // ]
+ // }
+ //
+ const order = this.parseOrder (response);
+ return this.extend (order, {
+ 'id': id.toString (),
+ });
}
async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -51876,48 +63211,7 @@ module.exports = class exmo extends Exchange {
return this.parseTrades (trades, market, since, limit);
}
- updateCachedOrders (openOrders, symbol) {
- // update local cache with open orders
- for (let j = 0; j < openOrders.length; j++) {
- const id = openOrders[j]['id'];
- this.orders[id] = openOrders[j];
- }
- const openOrdersIndexedById = this.indexBy (openOrders, 'id');
- const cachedOrderIds = Object.keys (this.orders);
- for (let k = 0; k < cachedOrderIds.length; k++) {
- // match each cached order to an order in the open orders array
- // possible reasons why a cached order may be missing in the open orders array:
- // - order was closed or canceled -> update cache
- // - symbol mismatch (e.g. cached BTC/USDT, fetched ETH/USDT) -> skip
- const id = cachedOrderIds[k];
- let order = this.orders[id];
- if (!(id in openOrdersIndexedById)) {
- // cached order is not in open orders array
- // if we fetched orders by symbol and it doesn't match the cached order -> won't update the cached order
- if (symbol !== undefined && symbol !== order['symbol']) {
- continue;
- }
- // order is cached but not present in the list of open orders -> mark the cached order as closed
- if (order['status'] === 'open') {
- order = this.extend (order, {
- 'status': 'closed', // likewise it might have been canceled externally (unnoticed by "us")
- 'cost': undefined,
- 'filled': order['amount'],
- 'remaining': 0.0,
- });
- if (order['cost'] === undefined) {
- if (order['filled'] !== undefined) {
- order['cost'] = order['filled'] * order['price'];
- }
- }
- this.orders[id] = order;
- }
- }
- }
- return this.toArray (this.orders);
- }
-
- async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privatePostUserOpenOrders (params);
const marketIds = Object.keys (response);
@@ -51931,19 +63225,6 @@ module.exports = class exmo extends Exchange {
const parsedOrders = this.parseOrders (response[marketId], market);
orders = this.arrayConcat (orders, parsedOrders);
}
- this.updateCachedOrders (orders, symbol);
- return this.filterBySymbolSinceLimit (this.toArray (this.orders), symbol, since, limit);
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.fetchOrders (symbol, since, limit, params);
- const orders = this.filterBy (this.orders, 'status', 'open');
- return this.filterBySymbolSinceLimit (orders, symbol, since, limit);
- }
-
- async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.fetchOrders (symbol, since, limit, params);
- const orders = this.filterBy (this.orders, 'status', 'closed');
return this.filterBySymbolSinceLimit (orders, symbol, since, limit);
}
@@ -52035,15 +63316,15 @@ module.exports = class exmo extends Exchange {
}
lastTradeTimestamp = trades[numTransactions - 1]['timestamp'];
}
+ let status = this.safeString (order, 'status'); // in case we need to redefine it for canceled orders
let remaining = undefined;
if (amount !== undefined) {
remaining = amount - filled;
- }
- let status = this.safeString (order, 'status'); // in case we need to redefine it for canceled orders
- if (filled >= amount) {
- status = 'closed';
- } else {
- status = 'open';
+ if (filled >= amount) {
+ status = 'closed';
+ } else {
+ status = 'open';
+ }
}
if (market === undefined) {
market = this.getMarketFromTrades (trades);
@@ -52080,8 +63361,10 @@ module.exports = class exmo extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -52351,13 +63634,13 @@ module.exports = class exmo extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],80:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],80:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, AuthenticationError, ExchangeNotAvailable } = require ('./base/errors');
+const { ExchangeError, AuthenticationError, ExchangeNotAvailable, ArgumentsRequired } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -52370,9 +63653,16 @@ module.exports = class exx extends Exchange {
'rateLimit': 1000 / 10,
'userAgent': this.userAgents['chrome'],
'has': {
- 'fetchOrder': true,
- 'fetchTickers': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/37770292-fbf613d0-2de4-11e8-9f79-f2dc451b8ccb.jpg',
@@ -52437,6 +63727,7 @@ module.exports = class exx extends Exchange {
},
},
'commonCurrencies': {
+ 'DOS': 'DEMOS',
'TV': 'TIV', // Ti-Value
},
'exceptions': {
@@ -52548,7 +63839,7 @@ module.exports = class exx extends Exchange {
};
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -52671,8 +63962,10 @@ module.exports = class exx extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': order['type'],
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -52703,7 +63996,6 @@ module.exports = class exx extends Exchange {
'type': side,
'info': response,
}, market);
- this.orders[id] = order;
return order;
}
@@ -52731,6 +64023,9 @@ module.exports = class exx extends Exchange {
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument');
+ }
const market = this.market (symbol);
const request = {
'currency': market['id'],
@@ -52804,7 +64099,7 @@ module.exports = class exx extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],81:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],81:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -52827,18 +64122,25 @@ module.exports = class fcoin extends Exchange {
'accountsById': undefined,
'hostname': 'fcoin.com',
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': false,
'fetchDepositAddress': false,
+ 'fetchMarkets': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
'fetchOrder': true,
- 'fetchOrders': true,
'fetchOrderBook': true,
'fetchOrderBooks': false,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTradingLimits': false,
'withdraw': false,
- 'fetchCurrencies': false,
},
'timeframes': {
'1m': 'M1',
@@ -53182,16 +64484,11 @@ module.exports = class fcoin extends Exchange {
if (tickerType !== undefined) {
const parts = tickerType.split ('.');
const id = parts[1];
- if (id in this.markets_by_id) {
- market = this.markets_by_id[id];
- }
+ symbol = this.safeSymbol (id, market);
}
}
const values = ticker['ticker'];
const last = this.safeFloat (values, 0);
- if (market !== undefined) {
- symbol = market['symbol'];
- }
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -53250,6 +64547,17 @@ module.exports = class fcoin extends Exchange {
};
}
+ async fetchTime (params = {}) {
+ const response = await this.publicGetServerTime (params);
+ //
+ // {
+ // "status": 0,
+ // "data": 1523430502977
+ // }
+ //
+ return this.safeInteger (response, 'data');
+ }
+
async fetchTrades (symbol, since = undefined, limit = 50, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -53340,13 +64648,9 @@ module.exports = class fcoin extends Exchange {
const id = this.safeString (order, 'id');
const side = this.safeString (order, 'side');
const status = this.parseOrderStatus (this.safeString (order, 'state'));
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
+ const marketId = this.safeString (order, 'symbol');
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
const orderType = this.safeString (order, 'type');
const timestamp = this.safeInteger (order, 'created_at');
const amount = this.safeFloat (order, 'amount');
@@ -53371,14 +64675,12 @@ module.exports = class fcoin extends Exchange {
const feeRebate = this.safeFloat (order, 'fees_income');
if ((feeRebate !== undefined) && (feeRebate > 0)) {
if (market !== undefined) {
- symbol = market['symbol'];
feeCurrency = (side === 'buy') ? market['quote'] : market['base'];
}
feeCost = -feeRebate;
} else {
feeCost = this.safeFloat (order, 'fill_fees');
if (market !== undefined) {
- symbol = market['symbol'];
feeCurrency = (side === 'buy') ? market['base'] : market['quote'];
}
}
@@ -53391,8 +64693,10 @@ module.exports = class fcoin extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': orderType,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'remaining': remaining,
@@ -53443,7 +64747,7 @@ module.exports = class fcoin extends Exchange {
return this.parseOrders (response['data'], market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
return [
this.safeTimestamp (ohlcv, 'id'),
this.safeFloat (ohlcv, 'open'),
@@ -53471,7 +64775,8 @@ module.exports = class fcoin extends Exchange {
request['before'] = this.sum (sinceInSeconds, timerange) - 1;
}
const response = await this.marketGetCandlesTimeframeSymbol (this.extend (request, params));
- return this.parseOHLCVs (response['data'], market, timeframe, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
nonce () {
@@ -53508,7 +64813,7 @@ module.exports = class fcoin extends Exchange {
auth += this.urlencode (query);
}
}
- const payload = this.stringToBase64 (this.encode (auth));
+ const payload = this.stringToBase64 (auth);
let signature = this.hmac (payload, this.encode (this.secret), 'sha1', 'binary');
signature = this.decode (this.stringToBase64 (signature));
headers = {
@@ -53538,7 +64843,7 @@ module.exports = class fcoin extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],82:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],82:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -53583,10 +64888,17 @@ module.exports = class flowbtc extends Exchange {
'version': 'v1',
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/28162465-cd815d4c-67cf-11e7-8e57-438bea0523a2.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87443317-01c0d080-c5fe-11ea-95c2-9ebe1a8fafd9.jpg',
'api': 'https://publicapi.flowbtc.com.br',
'www': 'https://www.flowbtc.com.br',
'doc': 'https://www.flowbtc.com.br/api.html',
@@ -53843,7 +65155,7 @@ module.exports = class flowbtc extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],84:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],84:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -53860,13 +65172,19 @@ module.exports = class foxbit extends Exchange {
'name': 'FoxBit',
'countries': [ 'BR' ],
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'rateLimit': 1000,
'version': 'v1',
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27991413-11b40d42-647f-11e7-91ee-78ced874dd09.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87443320-01c0d080-c5fe-11ea-92e2-4ef56d32b026.jpg',
'api': {
'public': 'https://api.blinktrade.com/api',
'private': 'https://api.blinktrade.com/tapi',
@@ -54102,14 +65420,14 @@ module.exports = class foxbit extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],85:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],85:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { TICK_SIZE } = require ('./base/functions/number');
-const { ExchangeError, InvalidOrder, BadRequest, InsufficientFunds, OrderNotFound } = require ('./base/errors');
+const { ExchangeError, InvalidOrder, BadRequest, InsufficientFunds, OrderNotFound, AuthenticationError } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -54122,12 +65440,13 @@ module.exports = class ftx extends Exchange {
'rateLimit': 100,
'certified': true,
'pro': true,
+ 'hostname': 'ftx.com', // or ftx.us
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/67149189-df896480-f2b0-11e9-8816-41593e17f9ec.jpg',
'www': 'https://ftx.com',
'api': {
- 'public': 'https://ftx.com',
- 'private': 'https://ftx.com',
+ 'public': 'https://{hostname}',
+ 'private': 'https://{hostname}',
},
'doc': 'https://github.com/ftexchange/ftx',
'fees': 'https://ftexchange.zendesk.com/hc/en-us/articles/360024479432-Fees',
@@ -54135,11 +65454,16 @@ module.exports = class ftx extends Exchange {
},
'has': {
'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': false,
'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
'fetchFundingFees': false,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
@@ -54171,12 +65495,24 @@ module.exports = class ftx extends Exchange {
'markets/{market_name}/orderbook', // ?depth={depth}
'markets/{market_name}/trades', // ?limit={limit}&start_time={start_time}&end_time={end_time}
'markets/{market_name}/candles', // ?resolution={resolution}&limit={limit}&start_time={start_time}&end_time={end_time}
+ // futures
'futures',
'futures/{future_name}',
'futures/{future_name}/stats',
'funding_rates',
+ 'indexes/{index_name}/weights',
+ 'expired_futures',
+ 'indexes/{market_name}/candles', // ?resolution={resolution}&limit={limit}&start_time={start_time}&end_time={end_time}
+ // leverage tokens
'lt/tokens',
'lt/{token_name}',
+ // options
+ 'options/requests',
+ 'options/trades',
+ 'stats/24h_options_volume',
+ 'options/historical_volumes/BTC',
+ 'options/open_interest/BTC',
+ 'options/historical_open_interest/BTC',
],
},
'private': {
@@ -54185,6 +65521,7 @@ module.exports = class ftx extends Exchange {
'positions',
'wallet/coins',
'wallet/balances',
+ 'wallet/all_balances',
'wallet/deposit_address/{coin}',
'wallet/deposits',
'wallet/withdrawals',
@@ -54193,32 +65530,60 @@ module.exports = class ftx extends Exchange {
'orders/{order_id}',
'orders/by_client_id/{client_order_id}',
'conditional_orders', // ?market={market}
+ 'conditional_orders/{conditional_order_id}/triggers',
'conditional_orders/history', // ?market={market}
'fills', // ?market={market}
'funding_payments',
+ // leverage tokens
'lt/balances',
'lt/creations',
'lt/redemptions',
+ // subaccounts
'subaccounts',
'subaccounts/{nickname}/balances',
+ // otc
+ 'otc/quotes/{quoteId}',
+ // options
+ 'options/my_requests',
+ 'options/requests/{request_id}/quotes',
+ 'options/my_quotes',
+ 'options/account_info',
+ 'options/positions',
+ 'options/fills',
],
'post': [
'account/leverage',
'wallet/withdrawals',
'orders',
'conditional_orders',
+ 'orders/{order_id}/modify',
+ 'orders/by_client_id/{client_order_id}/modify',
+ 'conditional_orders/{order_id}/modify',
+ // leverage tokens
'lt/{token_name}/create',
'lt/{token_name}/redeem',
+ // subaccounts
'subaccounts',
'subaccounts/update_name',
'subaccounts/transfer',
+ // otc
+ 'otc/quotes/{quote_id}/accept',
+ 'otc/quotes',
+ // options
+ 'options/requests',
+ 'options/requests/{request_id}/quotes',
+ 'options/quotes/{quote_id}/accept',
],
'delete': [
'orders/{order_id}',
'orders/by_client_id/{client_order_id}',
'orders',
'conditional_orders/{order_id}',
+ // subaccounts
'subaccounts',
+ // options
+ 'options/requests/{request_id}',
+ 'options/quotes/{quote_id}',
],
},
},
@@ -54253,11 +65618,13 @@ module.exports = class ftx extends Exchange {
},
'exceptions': {
'exact': {
+ 'Not logged in': AuthenticationError, // {"error":"Not logged in","success":false}
'Not enough balances': InsufficientFunds, // {"error":"Not enough balances","success":false}
'InvalidPrice': InvalidOrder, // {"error":"Invalid price","success":false}
'Size too small': InvalidOrder, // {"error":"Size too small","success":false}
'Missing parameter price': InvalidOrder, // {"error":"Missing parameter price","success":false}
'Order not found': OrderNotFound, // {"error":"Order not found","success":false}
+ 'Order already closed': InvalidOrder, // {"error":"Order already closed","success":false}
},
'broad': {
'Invalid parameter': BadRequest, // {"error":"Invalid parameter start_time","success":false}
@@ -54280,6 +65647,10 @@ module.exports = class ftx extends Exchange {
'fetchOrders': {
'method': 'privateGetOrdersHistory', // privateGetConditionalOrdersHistory
},
+ 'sign': {
+ 'ftx.com': 'FTX',
+ 'ftx.us': 'FTXUS',
+ },
},
});
}
@@ -54597,7 +65968,7 @@ module.exports = class ftx extends Exchange {
return this.parseOrderBook (result);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// "close":177.23,
@@ -54619,12 +65990,29 @@ module.exports = class ftx extends Exchange {
];
}
+ getMarketId (symbol, key, params = {}) {
+ const parts = this.getMarketParams (symbol, key, params);
+ return this.safeString (parts, 1, symbol);
+ }
+
+ getMarketParams (symbol, key, params = {}) {
+ let market = undefined;
+ let marketId = undefined;
+ if (symbol in this.markets) {
+ market = this.market (symbol);
+ marketId = market['id'];
+ } else {
+ marketId = this.safeString (params, key, symbol);
+ }
+ return [ market, marketId ];
+ }
+
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
- const market = this.market (symbol);
+ const [ market, marketId ] = this.getMarketParams (symbol, 'market_name', params);
const request = {
- 'market_name': market['id'],
'resolution': this.timeframes[timeframe],
+ 'market_name': marketId,
};
// max 1501 candles, including the current candle when since is not specified
limit = (limit === undefined) ? 1501 : limit;
@@ -54760,9 +66148,9 @@ module.exports = class ftx extends Exchange {
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
- const market = this.market (symbol);
+ const [ market, marketId ] = this.getMarketParams (symbol, 'market_name', params);
const request = {
- 'market_name': market['id'],
+ 'market_name': marketId,
};
if (since !== undefined) {
request['start_time'] = parseInt (since / 1000);
@@ -54883,13 +66271,14 @@ module.exports = class ftx extends Exchange {
'new': 'open',
'open': 'open',
'closed': 'closed', // filled or canceled
+ 'triggered': 'closed',
};
return this.safeString (statuses, status, status);
}
parseOrder (order, market = undefined) {
//
- // limit orders - fetchOrder, fetchOrders, fetchOpenOrders, createOrder
+ // limit orders - fetchOrder, fetchOrders, fetchOpenOrders, createOrder, editOrder
//
// {
// "createdAt": "2019-03-05T09:56:55.728933+00:00",
@@ -54949,23 +66338,80 @@ module.exports = class ftx extends Exchange {
// "reduceOnly": false
// }
//
+ // editOrder (conditional, stop, trailing stop, take profit)
+ //
+ // {
+ // "createdAt": "2019-03-05T09:56:55.728933+00:00",
+ // "future": "XRP-PERP",
+ // "id": 9596912,
+ // "market": "XRP-PERP",
+ // "triggerPrice": 0.306225,
+ // "orderId": null,
+ // "side": "sell",
+ // "size": 31431,
+ // "status": "open",
+ // "type": "stop",
+ // "orderPrice": null,
+ // "error": null,
+ // "triggeredAt": null,
+ // "reduceOnly": false,
+ // "orderType": "market",
+ // "filledSize": 0,
+ // "avgFillPrice": null,
+ // "retryUntilFilled": false
+ // }
+ //
+ // canceled order with a closed status
+ //
+ // {
+ // "avgFillPrice":null,
+ // "clientId":null,
+ // "createdAt":"2020-09-01T13:45:57.119695+00:00",
+ // "filledSize":0.0,
+ // "future":null,
+ // "id":8553541288,
+ // "ioc":false,
+ // "liquidation":false,
+ // "market":"XRP/USDT",
+ // "postOnly":false,
+ // "price":0.5,
+ // "reduceOnly":false,
+ // "remainingSize":0.0,
+ // "side":"sell",
+ // "size":46.0,
+ // "status":"closed",
+ // "type":"limit"
+ // }
+ //
const id = this.safeString (order, 'id');
const timestamp = this.parse8601 (this.safeString (order, 'createdAt'));
+ let status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const amount = this.safeFloat (order, 'size');
const filled = this.safeFloat (order, 'filledSize');
- const remaining = this.safeFloat (order, 'remainingSize');
+ let remaining = this.safeFloat (order, 'remainingSize');
+ if ((remaining === 0.0) && (amount !== undefined) && (filled !== undefined)) {
+ remaining = Math.max (amount - filled, 0);
+ if (remaining > 0) {
+ status = 'canceled';
+ }
+ }
let symbol = undefined;
const marketId = this.safeString (order, 'market');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ symbol = market['symbol'];
+ } else {
+ // support for delisted market ids
+ // https://github.com/ccxt/ccxt/issues/7113
+ symbol = marketId;
+ }
}
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
- const status = this.parseOrderStatus (this.safeString (order, 'status'));
const side = this.safeString (order, 'side');
const type = this.safeString (order, 'type');
- const amount = this.safeFloat (order, 'size');
const average = this.safeFloat (order, 'avgFillPrice');
const price = this.safeFloat2 (order, 'price', 'triggerPrice', average);
let cost = undefined;
@@ -54974,6 +66420,7 @@ module.exports = class ftx extends Exchange {
}
const lastTradeTimestamp = this.parse8601 (this.safeString (order, 'triggeredAt'));
const clientOrderId = this.safeString (order, 'clientId');
+ const stopPrice = this.safeFloat (order, 'triggerPrice');
return {
'info': order,
'id': id,
@@ -54983,8 +66430,10 @@ module.exports = class ftx extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -55010,6 +66459,11 @@ module.exports = class ftx extends Exchange {
// 'postOnly': false, // optional, default is false, limit or market orders only
// 'clientId': 'abcdef0123456789', // string, optional, client order id, limit or market orders only
};
+ const clientOrderId = this.safeString2 (params, 'clientId', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['clientId'] = clientOrderId;
+ params = this.omit (params, [ 'clientId', 'clientOrderId' ]);
+ }
let priceToPrecision = undefined;
if (price !== undefined) {
priceToPrecision = parseFloat (this.priceToPrecision (symbol, price));
@@ -55085,6 +66539,104 @@ module.exports = class ftx extends Exchange {
return this.parseOrder (result, market);
}
+ async editOrder (id, symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {};
+ let method = undefined;
+ const clientOrderId = this.safeString2 (params, 'client_order_id', 'clientOrderId');
+ const triggerPrice = this.safeFloat (params, 'triggerPrice');
+ const orderPrice = this.safeFloat (params, 'orderPrice');
+ const trailValue = this.safeFloat (params, 'trailValue');
+ params = this.omit (params, [ 'client_order_id', 'clientOrderId', 'triggerPrice', 'orderPrice', 'trailValue' ]);
+ const triggerPriceIsDefined = (triggerPrice !== undefined);
+ const orderPriceIsDefined = (orderPrice !== undefined);
+ const trailValueIsDefined = (trailValue !== undefined);
+ if (triggerPriceIsDefined || orderPriceIsDefined || trailValueIsDefined) {
+ method = 'privatePostConditionalOrdersOrderIdModify';
+ request['order_id'] = id;
+ if (triggerPriceIsDefined) {
+ request['triggerPrice'] = parseFloat (this.priceToPrecision (symbol, triggerPrice));
+ }
+ if (orderPriceIsDefined) {
+ // only for stop limit or take profit limit orders
+ request['orderPrice'] = parseFloat (this.priceToPrecision (symbol, orderPrice));
+ }
+ if (trailValueIsDefined) {
+ // negative for sell orders, positive for buy orders
+ request['trailValue'] = parseFloat (this.priceToPrecision (symbol, trailValue));
+ }
+ } else {
+ if (clientOrderId === undefined) {
+ method = 'privatePostOrdersByClientIdClientOrderIdModify';
+ request['client_order_id'] = clientOrderId;
+ // request['clientId'] = clientOrderId;
+ } else {
+ method = 'privatePostOrdersOrderIdModify';
+ request['order_id'] = id;
+ }
+ if (price !== undefined) {
+ request['price'] = parseFloat (this.priceToPrecision (symbol, price));
+ }
+ }
+ if (amount !== undefined) {
+ request['size'] = parseFloat (this.amountToPrecision (symbol, amount));
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // regular order
+ //
+ // {
+ // "success": true,
+ // "result": {
+ // "createdAt": "2019-03-05T11:56:55.728933+00:00",
+ // "filledSize": 0,
+ // "future": "XRP-PERP",
+ // "id": 9596932,
+ // "market": "XRP-PERP",
+ // "price": 0.326525,
+ // "remainingSize": 31431,
+ // "side": "sell",
+ // "size": 31431,
+ // "status": "open",
+ // "type": "limit",
+ // "reduceOnly": false,
+ // "ioc": false,
+ // "postOnly": false,
+ // "clientId": null,
+ // }
+ // }
+ //
+ // conditional trigger order
+ //
+ // {
+ // "success": true,
+ // "result": {
+ // "createdAt": "2019-03-05T09:56:55.728933+00:00",
+ // "future": "XRP-PERP",
+ // "id": 9596912,
+ // "market": "XRP-PERP",
+ // "triggerPrice": 0.306225,
+ // "orderId": null,
+ // "side": "sell",
+ // "size": 31431,
+ // "status": "open",
+ // "type": "stop",
+ // "orderPrice": null,
+ // "error": null,
+ // "triggeredAt": null,
+ // "reduceOnly": false,
+ // "orderType": "market",
+ // "filledSize": 0,
+ // "avgFillPrice": null,
+ // "retryUntilFilled": false
+ // }
+ // }
+ //
+ const result = this.safeValue (response, 'result', {});
+ return this.parseOrder (result, market);
+ }
+
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const request = {
@@ -55096,10 +66648,17 @@ module.exports = class ftx extends Exchange {
const defaultMethod = this.safeString (options, 'method', 'privateDeleteOrdersOrderId');
let method = this.safeString (params, 'method', defaultMethod);
const type = this.safeValue (params, 'type');
- if ((type === 'stop') || (type === 'trailingStop') || (type === 'takeProfit')) {
- method = 'privateDeleteConditionalOrdersOrderId';
+ const clientOrderId = this.safeValue2 (params, 'client_order_id', 'clientOrderId');
+ if (clientOrderId === undefined) {
+ request['order_id'] = parseInt (id);
+ if ((type === 'stop') || (type === 'trailingStop') || (type === 'takeProfit')) {
+ method = 'privateDeleteConditionalOrdersOrderId';
+ }
+ } else {
+ request['client_order_id'] = clientOrderId;
+ method = 'privateDeleteOrdersByClientIdClientOrderId';
}
- const query = this.omit (params, [ 'method', 'type' ]);
+ const query = this.omit (params, [ 'method', 'type', 'client_order_id', 'clientOrderId' ]);
const response = await this[method] (this.extend (request, query));
//
// {
@@ -55118,10 +66677,9 @@ module.exports = class ftx extends Exchange {
'conditionalOrdersOnly': false, // cancel conditional orders only
'limitOrdersOnly': false, // cancel existing limit orders (non-conditional orders) only
};
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['market'] = market['id'];
+ const marketId = this.getMarketId (symbol, 'market', params);
+ if (marketId !== undefined) {
+ request['market'] = marketId;
}
const response = await this.privateDeleteOrders (this.extend (request, params));
const result = this.safeValue (response, 'result', {});
@@ -55136,10 +66694,17 @@ module.exports = class ftx extends Exchange {
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- const request = {
- 'order_id': id,
- };
- const response = await this.privateGetOrdersOrderId (this.extend (request, params));
+ const request = {};
+ const clientOrderId = this.safeValue2 (params, 'client_order_id', 'clientOrderId');
+ let method = 'privateGetOrdersOrderId';
+ if (clientOrderId === undefined) {
+ request['order_id'] = id;
+ } else {
+ request['client_order_id'] = clientOrderId;
+ params = this.omit (params, [ 'client_order_id', 'clientOrderId']);
+ method = 'privateGetOrdersByClientIdClientOrderId';
+ }
+ const response = await this[method] (this.extend (request, params));
//
// {
// "success": true,
@@ -55170,10 +66735,9 @@ module.exports = class ftx extends Exchange {
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['market'] = market['id'];
+ const [ market, marketId ] = this.getMarketParams (symbol, 'market', params);
+ if (marketId !== undefined) {
+ request['market'] = marketId;
}
// support for canceling conditional orders
// https://github.com/ccxt/ccxt/issues/6669
@@ -55218,10 +66782,9 @@ module.exports = class ftx extends Exchange {
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['market'] = market['id'];
+ const [ market, marketId ] = this.getMarketParams (symbol, 'market', params);
+ if (marketId !== undefined) {
+ request['market'] = marketId;
}
if (limit !== undefined) {
request['limit'] = limit; // default 100, max 100
@@ -55271,10 +66834,11 @@ module.exports = class ftx extends Exchange {
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'market': market['id'],
- };
+ const [ market, marketId ] = this.getMarketParams (symbol, 'market', params);
+ const request = {};
+ if (marketId !== undefined) {
+ request['market'] = marketId;
+ }
if (limit !== undefined) {
request['limit'] = limit;
}
@@ -55320,6 +66884,9 @@ module.exports = class ftx extends Exchange {
// 'password': 'string', // optional withdrawal password if it is required for your account
// 'code': '192837', // optional 2fa code if it is required for your account
};
+ if (this.password !== undefined) {
+ request['password'] = this.password;
+ }
if (tag !== undefined) {
request['tag'] = tag;
}
@@ -55344,6 +66911,60 @@ module.exports = class ftx extends Exchange {
return this.parseTransaction (result, currency);
}
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccount (params);
+ //
+ // {
+ // "result":{
+ // "backstopProvider":false,
+ // "chargeInterestOnNegativeUsd":false,
+ // "collateral":2830.2567913677476,
+ // "freeCollateral":2829.670741867416,
+ // "initialMarginRequirement":0.05,
+ // "leverage":20.0,
+ // "liquidating":false,
+ // "maintenanceMarginRequirement":0.03,
+ // "makerFee":0.0,
+ // "marginFraction":null,
+ // "openMarginFraction":null,
+ // "positionLimit":null,
+ // "positionLimitUsed":null,
+ // "positions":[
+ // {
+ // "collateralUsed":0.0,
+ // "cost":0.0,
+ // "entryPrice":null,
+ // "estimatedLiquidationPrice":null,
+ // "future":"XRP-PERP",
+ // "initialMarginRequirement":0.05,
+ // "longOrderSize":0.0,
+ // "maintenanceMarginRequirement":0.03,
+ // "netSize":0.0,
+ // "openSize":0.0,
+ // "realizedPnl":0.016,
+ // "shortOrderSize":0.0,
+ // "side":"buy",
+ // "size":0.0,
+ // "unrealizedPnl":0.0,
+ // }
+ // ],
+ // "spotLendingEnabled":false,
+ // "spotMarginEnabled":false,
+ // "takerFee":0.0007,
+ // "totalAccountValue":2830.2567913677476,
+ // "totalPositionSize":0.0,
+ // "useFttCollateral":true,
+ // "username":"igor.kroitor@gmail.com"
+ // },
+ // "success":true
+ // }
+ //
+ const result = this.safeValue (response, 'result', {});
+ // todo unify parsePosition/parsePositions
+ return this.safeValue (result, 'positions', []);
+ }
+
async fetchDepositAddress (code, params = {}) {
await this.loadMarkets ();
const currency = this.currency (code);
@@ -55381,7 +67002,7 @@ module.exports = class ftx extends Exchange {
return this.safeString (statuses, status, status);
}
- parseTransaction (transaction) {
+ parseTransaction (transaction, currency = undefined) {
//
// fetchDeposits
//
@@ -55413,14 +67034,19 @@ module.exports = class ftx extends Exchange {
// }
//
const code = this.safeCurrencyCode (this.safeString (transaction, 'coin'));
- const id = this.safeInteger (transaction, 'id');
+ const id = this.safeString (transaction, 'id');
const amount = this.safeFloat (transaction, 'size');
const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
const timestamp = this.parse8601 (this.safeString (transaction, 'time'));
const txid = this.safeString (transaction, 'txid');
- const address = this.safeString (transaction, 'address');
- const tag = this.safeString (transaction, 'tag');
+ let tag = undefined;
+ let address = this.safeValue (transaction, 'address');
+ if (typeof address !== 'string') {
+ tag = this.safeString (address, 'tag');
+ address = this.safeString (address, 'address');
+ }
const fee = this.safeFloat (transaction, 'fee');
+ const type = ('destinationName' in transaction) ? 'withdrawal' : 'deposit';
return {
'info': transaction,
'id': id,
@@ -55428,12 +67054,12 @@ module.exports = class ftx extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'addressFrom': undefined,
- 'address': undefined,
+ 'address': address,
'addressTo': address,
'tagFrom': undefined,
'tag': tag,
- 'tagTo': undefined,
- 'type': undefined,
+ 'tagTo': tag,
+ 'type': type,
'amount': amount,
'currency': code,
'status': status,
@@ -55467,10 +67093,14 @@ module.exports = class ftx extends Exchange {
// }
//
const result = this.safeValue (response, 'result', []);
- return this.parseTransactions (result);
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ return this.parseTransactions (result, currency, since, limit);
}
- async fetchWithdrawals (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privateGetWalletWithdrawals (params);
//
@@ -55490,13 +67120,18 @@ module.exports = class ftx extends Exchange {
// }
//
const result = this.safeValue (response, 'result', []);
- return this.parseTransactions (result);
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ return this.parseTransactions (result, currency, since, limit);
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
let request = '/api/' + this.implodeParams (path, params);
const query = this.omit (params, this.extractParams (path));
- let url = this.urls['api'][api] + request;
+ const baseUrl = this.implodeParams (this.urls['api'][api], { 'hostname': this.hostname });
+ let url = baseUrl + request;
if (method !== 'POST') {
if (Object.keys (query).length) {
const suffix = '?' + this.urlencode (query);
@@ -55508,17 +67143,21 @@ module.exports = class ftx extends Exchange {
this.checkRequiredCredentials ();
const timestamp = this.milliseconds ().toString ();
let auth = timestamp + method + request;
- headers = {
- 'FTX-KEY': this.apiKey,
- 'FTX-TS': timestamp,
- };
- if (method === 'POST') {
+ headers = {};
+ if ((method === 'POST') || (method === 'DELETE')) {
body = this.json (query);
auth += body;
headers['Content-Type'] = 'application/json';
}
const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256');
- headers['FTX-SIGN'] = signature;
+ const options = this.safeValue (this.options, 'sign', {});
+ const headerPrefix = this.safeString (options, this.hostname, 'FTX');
+ const keyField = headerPrefix + '-KEY';
+ const tsField = headerPrefix + '-TS';
+ const signField = headerPrefix + '-SIGN';
+ headers[keyField] = this.apiKey;
+ headers[tsField] = timestamp;
+ headers[signField] = signature;
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
@@ -55542,204 +67181,7 @@ module.exports = class ftx extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],86:[function(require,module,exports){
-'use strict';
-
-// ---------------------------------------------------------------------------
-
-const Exchange = require ('./base/Exchange');
-const { ExchangeError } = require ('./base/errors');
-
-// ---------------------------------------------------------------------------
-
-module.exports = class fybse extends Exchange {
- describe () {
- return this.deepExtend (super.describe (), {
- 'id': 'fybse',
- 'name': 'FYB-SE',
- 'countries': [ 'SE' ], // Sweden
- 'has': {
- 'CORS': false,
- },
- 'rateLimit': 1500,
- 'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27766512-31019772-5edb-11e7-8241-2e675e6797f1.jpg',
- 'api': 'https://www.fybse.se/api/SEK',
- 'www': 'https://www.fybse.se',
- 'doc': 'https://fyb.docs.apiary.io',
- },
- 'api': {
- 'public': {
- 'get': [
- 'ticker',
- 'tickerdetailed',
- 'orderbook',
- 'trades',
- ],
- },
- 'private': {
- 'post': [
- 'test',
- 'getaccinfo',
- 'getpendingorders',
- 'getorderhistory',
- 'cancelpendingorder',
- 'placeorder',
- 'withdraw',
- ],
- },
- },
- 'markets': {
- 'BTC/SEK': { 'id': 'SEK', 'symbol': 'BTC/SEK', 'base': 'BTC', 'quote': 'SEK' },
- },
- });
- }
-
- async fetchBalance (params = {}) {
- await this.loadMarkets ();
- const response = await this.privatePostGetaccinfo (params);
- const btc = this.safeFloat (response, 'btcBal');
- const symbol = this.symbols[0];
- const quote = this.markets[symbol]['quote'];
- const lowercase = quote.toLowerCase () + 'Bal';
- const fiat = this.safeFloat (response, lowercase);
- const crypto = this.account ();
- crypto['total'] = btc;
- const result = { 'BTC': crypto };
- result[quote] = this.account ();
- result[quote]['total'] = fiat;
- result['info'] = response;
- return this.parseBalance (result);
- }
-
- async fetchOrderBook (symbol, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const response = await this.publicGetOrderbook (params);
- return this.parseOrderBook (response);
- }
-
- async fetchTicker (symbol, params = {}) {
- await this.loadMarkets ();
- const ticker = await this.publicGetTickerdetailed (params);
- const timestamp = this.milliseconds ();
- const last = this.safeFloat (ticker, 'last');
- const volume = this.safeFloat (ticker, 'vol');
- return {
- 'symbol': symbol,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'high': undefined,
- 'low': undefined,
- 'bid': this.safeFloat (ticker, 'bid'),
- 'bidVolume': undefined,
- 'ask': this.safeFloat (ticker, 'ask'),
- 'askVolume': undefined,
- 'vwap': undefined,
- 'open': undefined,
- 'close': last,
- 'last': last,
- 'previousClose': undefined,
- 'change': undefined,
- 'percentage': undefined,
- 'average': undefined,
- 'baseVolume': volume,
- 'quoteVolume': undefined,
- 'info': ticker,
- };
- }
-
- parseTrade (trade, market = undefined) {
- const timestamp = this.safeTimestamp (trade, 'date');
- const id = this.safeString (trade, 'tid');
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- const price = this.safeFloat (trade, 'price');
- const amount = this.safeFloat (trade, 'amount');
- let cost = undefined;
- if (price !== undefined) {
- if (amount !== undefined) {
- cost = price * amount;
- }
- }
- return {
- 'id': id,
- 'info': trade,
- 'order': undefined,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'symbol': symbol,
- 'type': undefined,
- 'side': undefined,
- 'takerOrMaker': undefined,
- 'price': price,
- 'amount': amount,
- 'cost': cost,
- 'fee': undefined,
- };
- }
-
- async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const response = await this.publicGetTrades (params);
- return this.parseTrades (response, market, since, limit);
- }
-
- async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'qty': amount,
- 'price': price,
- 'type': side[0].toUpperCase (),
- };
- const response = await this.privatePostPlaceorder (this.extend (request, params));
- return {
- 'info': response,
- 'id': response['pending_oid'],
- };
- }
-
- async cancelOrder (id, symbol = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'orderNo': id,
- };
- return await this.privatePostCancelpendingorder (this.extend (request, params));
- }
-
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- let url = this.urls['api'] + '/' + path;
- if (api === 'public') {
- url += '.json';
- } else {
- this.checkRequiredCredentials ();
- const nonce = this.nonce ();
- body = this.urlencode (this.extend ({ 'timestamp': nonce }, params));
- headers = {
- 'Content-Type': 'application/x-www-form-urlencoded',
- 'key': this.apiKey,
- 'sig': this.hmac (this.encode (body), this.encode (this.secret), 'sha1'),
- };
- }
- return { 'url': url, 'method': method, 'body': body, 'headers': headers };
- }
-
- async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- const response = await this.fetch2 (path, api, method, params, headers, body);
- if (api === 'private') {
- if ('error' in response) {
- if (response['error']) {
- throw new ExchangeError (this.id + ' ' + this.json (response));
- }
- }
- }
- return response;
- }
-};
-
-},{"./base/Exchange":7,"./base/errors":9}],87:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],86:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -55759,22 +67201,30 @@ module.exports = class gateio extends Exchange {
'rateLimit': 1000,
'pro': true,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'createMarketOrder': false,
- 'fetchTickers': true,
- 'withdraw': true,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
- 'fetchTransactions': true,
'createDepositAddress': true,
- 'fetchDepositAddress': true,
+ 'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': false,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
- 'fetchOrderTrades': true,
- 'fetchOrders': true,
'fetchOrder': true,
- 'fetchMyTrades': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': 60,
@@ -55809,6 +67259,7 @@ module.exports = class gateio extends Exchange {
'get': [
'candlestick2/{id}',
'pairs',
+ 'coininfo',
'marketinfo',
'marketlist',
'coininfo',
@@ -55886,7 +67337,6 @@ module.exports = class gateio extends Exchange {
},
},
'options': {
- 'fetchTradesMethod': 'public_get_tradehistory_id', // 'public_get_tradehistory_id_tid'
'limits': {
'cost': {
'min': {
@@ -55898,12 +67348,94 @@ module.exports = class gateio extends Exchange {
},
},
'commonCurrencies': {
+ 'BOX': 'DefiBox',
'BTCBEAR': 'BEAR',
'BTCBULL': 'BULL',
+ 'TNC': 'Trinity Network Credit',
},
});
}
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCoininfo (params);
+ //
+ // {
+ // "result":"true",
+ // "coins":[
+ // {
+ // "CNYX":{
+ // "delisted":0,
+ // "withdraw_disabled":1,
+ // "withdraw_delayed":0,
+ // "deposit_disabled":0,
+ // "trade_disabled":0
+ // }
+ // },
+ // {
+ // "USDT_ETH":{
+ // "delisted":0,
+ // "withdraw_disabled":1,
+ // "withdraw_delayed":0,
+ // "deposit_disabled":0,
+ // "trade_disabled":1
+ // }
+ // }
+ // ]
+ // }
+ //
+ const coins = this.safeValue (response, 'coins');
+ if (!coins) {
+ throw new ExchangeError (this.id + ' fetchCurrencies got an unrecognized response');
+ }
+ const result = {};
+ for (let i = 0; i < coins.length; i++) {
+ const coin = coins[i];
+ const ids = Object.keys (coin);
+ for (let j = 0; j < ids.length; j++) {
+ const id = ids[j];
+ const currency = coin[id];
+ const code = this.safeCurrencyCode (id);
+ const delisted = this.safeValue (currency, 'delisted', 0);
+ const withdrawDisabled = this.safeValue (currency, 'withdraw_disabled', 0);
+ const depositDisabled = this.safeValue (currency, 'deposit_disabled', 0);
+ const tradeDisabled = this.safeValue (currency, 'trade_disabled', 0);
+ const listed = (delisted === 0);
+ const withdrawEnabled = (withdrawDisabled === 0);
+ const depositEnabled = (depositDisabled === 0);
+ const tradeEnabled = (tradeDisabled === 0);
+ const active = listed && withdrawEnabled && depositEnabled && tradeEnabled;
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'active': active,
+ 'info': currency,
+ 'name': undefined,
+ 'fee': undefined,
+ 'precision': undefined,
+ 'limits': {
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ }
+ return result;
+ }
+
async fetchMarkets (params = {}) {
const response = await this.publicGetMarketinfo (params);
//
@@ -55951,7 +67483,7 @@ module.exports = class gateio extends Exchange {
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
const precision = {
- 'amount': 8,
+ 'amount': this.safeInteger (details, 'amount_decimal_places'),
'price': this.safeInteger (details, 'decimal_places'),
};
const amountLimits = {
@@ -56026,15 +67558,15 @@ module.exports = class gateio extends Exchange {
return this.parseOrderBook (response);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
// they return [ Timestamp, Volume, Close, High, Low, Open ]
return [
- parseInt (ohlcv[0]), // t
- parseFloat (ohlcv[5]), // o
- parseFloat (ohlcv[3]), // h
- parseFloat (ohlcv[4]), // l
- parseFloat (ohlcv[2]), // c
- parseFloat (ohlcv[1]), // v
+ this.safeInteger (ohlcv, 0), // t
+ this.safeFloat (ohlcv, 5), // o
+ this.safeFloat (ohlcv, 3), // h
+ this.safeFloat (ohlcv, 4), // l
+ this.safeFloat (ohlcv, 2), // c
+ this.safeFloat (ohlcv, 1), // v
];
}
@@ -56118,22 +67650,11 @@ module.exports = class gateio extends Exchange {
const ids = Object.keys (response);
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- const [ baseId, quoteId ] = id.split ('_');
- let base = baseId.toUpperCase ();
- let quote = quoteId.toUpperCase ();
- base = this.safeCurrencyCode (base);
- quote = this.safeCurrencyCode (quote);
- const symbol = base + '/' + quote;
- let market = undefined;
- if (symbol in this.markets) {
- market = this.markets[symbol];
- }
- if (id in this.markets_by_id) {
- market = this.markets_by_id[id];
- }
+ const market = this.safeMarket (id, undefined, '_');
+ const symbol = market['symbol'];
result[symbol] = this.parseTicker (response[id], market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -56219,7 +67740,12 @@ module.exports = class gateio extends Exchange {
const request = {
'id': market['id'],
};
- const method = this.safeString (this.options, 'fetchTradesMethod', 'public_get_tradehistory_id');
+ let method = undefined;
+ if ('tid' in params) {
+ method = 'publicGetTradeHistoryIdTid';
+ } else {
+ method = 'publicGetTradeHistoryId';
+ }
const response = await this[method] (this.extend (request, params));
return this.parseTrades (response['data'], market, since, limit);
}
@@ -56310,14 +67836,8 @@ module.exports = class gateio extends Exchange {
// }
//
const id = this.safeString2 (order, 'orderNumber', 'id');
- let symbol = undefined;
const marketId = this.safeString (order, 'currencyPair');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const timestamp = this.safeTimestamp2 (order, 'timestamp', 'ctime');
const lastTradeTimestamp = this.safeTimestamp (order, 'mtime');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
@@ -56353,8 +67873,10 @@ module.exports = class gateio extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': undefined,
'amount': amount,
'filled': filled,
@@ -56492,29 +68014,6 @@ module.exports = class gateio extends Exchange {
};
}
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- const prefix = (api === 'private') ? (api + '/') : '';
- let url = this.urls['api'][api] + this.version + '/1/' + prefix + this.implodeParams (path, params);
- const query = this.omit (params, this.extractParams (path));
- if (api === 'public') {
- if (Object.keys (query).length) {
- url += '?' + this.urlencode (query);
- }
- } else {
- this.checkRequiredCredentials ();
- const nonce = this.nonce ();
- const request = { 'nonce': nonce };
- body = this.urlencode (this.extend (request, query));
- const signature = this.hmac (this.encode (body), this.encode (this.secret), 'sha512');
- headers = {
- 'Key': this.apiKey,
- 'Sign': signature,
- 'Content-Type': 'application/x-www-form-urlencoded',
- };
- }
- return { 'url': url, 'method': method, 'body': body, 'headers': headers };
- }
-
async fetchTransactionsByType (type = undefined, code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
@@ -56639,15 +68138,42 @@ module.exports = class gateio extends Exchange {
this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
}
}
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const prefix = (api === 'private') ? (api + '/') : '';
+ let url = this.urls['api'][api] + this.version + '/1/' + prefix + this.implodeParams (path, params);
+ const query = this.omit (params, this.extractParams (path));
+ if (api === 'public') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else {
+ this.checkRequiredCredentials ();
+ const nonce = this.nonce ();
+ const request = { 'nonce': nonce };
+ body = this.rawencode (this.extend (request, query));
+ // gateio does not like the plus sign in the URL query
+ // https://github.com/ccxt/ccxt/issues/4529
+ body = body.replace ('+', ' ');
+ const signature = this.hmac (this.encode (body), this.encode (this.secret), 'sha512');
+ headers = {
+ 'Key': this.apiKey,
+ 'Sign': signature,
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ };
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
};
-},{"./base/Exchange":7,"./base/errors":9}],88:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],87:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, BadRequest, OrderNotFound, InvalidOrder, InvalidNonce, InsufficientFunds, AuthenticationError, PermissionDenied, NotSupported, OnMaintenance, RateLimitExceeded } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, BadRequest, OrderNotFound, InvalidOrder, InvalidNonce, InsufficientFunds, AuthenticationError, PermissionDenied, NotSupported, OnMaintenance, RateLimitExceeded, ExchangeNotAvailable } = require ('./base/errors');
+const { TICK_SIZE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -56660,22 +68186,29 @@ module.exports = class gemini extends Exchange {
'rateLimit': 1500, // 200 for private API
'version': 'v1',
'has': {
- 'fetchDepositAddress': false,
- 'createDepositAddress': true,
+ 'cancelOrder': true,
'CORS': false,
- 'fetchBidsAsks': false,
- 'fetchTickers': false,
- 'fetchMyTrades': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': false,
+ 'createDepositAddress': true,
'createMarketOrder': false,
- 'withdraw': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchBidsAsks': false,
+ 'fetchClosedOrders': false,
+ 'fetchDepositAddress': false,
+ 'fetchDeposits': false,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTransactions': true,
'fetchWithdrawals': false,
- 'fetchDeposits': false,
- 'fetchOHLCV': true,
+ 'withdraw': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27816857-ce7be644-6096-11e7-82d6-3c257263229c.jpg',
@@ -56692,7 +68225,11 @@ module.exports = class gemini extends Exchange {
'test': {
'public': 'https://api.sandbox.gemini.com',
'private': 'https://api.sandbox.gemini.com',
- 'web': 'https://docs.sandbox.gemini.com',
+ // use the true doc instead of the sandbox doc
+ // since they differ in parsing
+ // https://github.com/ccxt/ccxt/issues/7874
+ // https://github.com/ccxt/ccxt/issues/7894
+ 'web': 'https://docs.gemini.com',
},
'fees': [
'https://gemini.com/api-fee-schedule',
@@ -56709,6 +68246,7 @@ module.exports = class gemini extends Exchange {
'public': {
'get': [
'v1/symbols',
+ 'v1/pricefeed',
'v1/pubticker/{symbol}',
'v1/book/{symbol}',
'v1/trades/{symbol}',
@@ -56738,6 +68276,7 @@ module.exports = class gemini extends Exchange {
],
},
},
+ 'precisionMode': TICK_SIZE,
'fees': {
'trading': {
'taker': 0.0035,
@@ -56751,7 +68290,7 @@ module.exports = class gemini extends Exchange {
'406': InsufficientFunds, // Insufficient Funds
'429': RateLimitExceeded, // Rate Limiting was applied
'500': ExchangeError, // The server encountered an error
- '502': ExchangeError, // Technical issues are preventing the request from being satisfied
+ '502': ExchangeNotAvailable, // Technical issues are preventing the request from being satisfied
'503': OnMaintenance, // The exchange is down for maintenance
},
'timeframes': {
@@ -56798,10 +68337,12 @@ module.exports = class gemini extends Exchange {
},
'broad': {
'The Gemini Exchange is currently undergoing maintenance.': OnMaintenance, // The Gemini Exchange is currently undergoing maintenance. Please check https://status.gemini.com/ for more information.
+ 'We are investigating technical issues with the Gemini Exchange.': ExchangeNotAvailable, // We are investigating technical issues with the Gemini Exchange. Please check https://status.gemini.com/ for more information.
},
},
'options': {
'fetchMarketsMethod': 'fetch_markets_from_web',
+ 'fetchTickerMethod': 'fetchTickerV1', // fetchTickerV1, fetchTickerV2, fetchTickerV1AndV2
},
});
}
@@ -56811,7 +68352,7 @@ module.exports = class gemini extends Exchange {
return await this[method] (params);
}
- async fetchMarketsFromWeb (symbols = undefined, params = {}) {
+ async fetchMarketsFromWeb (params = {}) {
const response = await this.webGetRestApi (params);
const sections = response.split ('Symbols and minimums
');
const numSections = sections.length;
@@ -56835,73 +68376,62 @@ module.exports = class gemini extends Exchange {
const row = rows[i];
const cells = row.split ("\n"); // eslint-disable-line quotes
const numCells = cells.length;
- if (numCells < 9) {
+ if (numCells < 5) {
throw new NotSupported (error);
}
// [
- // 'BTC', // currency
+ // ' | btcusd', // currency
// ' | 0.00001 BTC (1e-5)', // min order size
// ' | 0.00000001 BTC (1e-8)', // tick size
- // ' | 0.01 USD', // usd price increment
- // ' | N/A', // btc price increment
- // ' | 0.0001 ETH (1e-4)', // eth price increment
- // ' | 0.0001 BCH (1e-4)', // bch price increment
- // ' | 0.001 LTC (1e-3)', // ltc price increment
+ // ' | 0.01 USD', // quote currency price increment
// ''
// ]
- //
- const uppercaseBaseId = cells[0].replace (' | ', '');
- const baseId = uppercaseBaseId.toLowerCase ();
- const base = this.safeCurrencyCode (baseId);
- const quoteIds = [ 'usd', 'btc', 'eth', 'bch', 'ltc' ];
+ const marketId = cells[0].replace (' | ', '');
+ // const base = this.safeCurrencyCode (baseId);
const minAmountString = cells[1].replace (' | ', '');
const minAmountParts = minAmountString.split (' ');
const minAmount = this.safeFloat (minAmountParts, 0);
const amountPrecisionString = cells[2].replace (' | ', '');
const amountPrecisionParts = amountPrecisionString.split (' ');
- const amountPrecision = this.precisionFromString (amountPrecisionParts[0]);
- for (let j = 0; j < quoteIds.length; j++) {
- const quoteId = quoteIds[j];
- const quote = this.safeCurrencyCode (quoteId);
- const pricePrecisionIndex = this.sum (3, j);
- const pricePrecisionString = cells[pricePrecisionIndex].replace (' | ', '');
- if (pricePrecisionString === 'N/A') {
- continue;
- }
- const pricePrecisionParts = pricePrecisionString.split (' ');
- const pricePrecision = this.precisionFromString (pricePrecisionParts[0]);
- const symbol = base + '/' + quote;
- const id = baseId + quoteId;
- const active = undefined;
- result.push ({
- 'id': id,
- 'info': row,
- 'symbol': symbol,
- 'base': base,
- 'quote': quote,
- 'baseId': baseId,
- 'quoteId': quoteId,
- 'active': active,
- 'precision': {
- 'amount': amountPrecision,
- 'price': pricePrecision,
+ const amountPrecision = this.safeFloat (amountPrecisionParts, 0);
+ const idLength = marketId.length - 0;
+ const quoteId = marketId.slice (idLength - 3, idLength);
+ const quote = this.safeCurrencyCode (quoteId);
+ const pricePrecisionString = cells[3].replace (' | ', '');
+ const pricePrecisionParts = pricePrecisionString.split (' ');
+ const pricePrecision = this.safeFloat (pricePrecisionParts, 0);
+ const baseId = marketId.replace (quoteId, '');
+ const base = this.safeCurrencyCode (baseId);
+ const symbol = base + '/' + quote;
+ const active = undefined;
+ result.push ({
+ 'id': marketId,
+ 'info': row,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'active': active,
+ 'precision': {
+ 'amount': amountPrecision,
+ 'price': pricePrecision,
+ },
+ 'limits': {
+ 'amount': {
+ 'min': minAmount,
+ 'max': undefined,
},
- 'limits': {
- 'amount': {
- 'min': minAmount,
- 'max': undefined,
- },
- 'price': {
- 'min': undefined,
- 'max': undefined,
- },
- 'cost': {
- 'min': undefined,
- 'max': undefined,
- },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
},
- });
- }
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ });
}
return result;
}
@@ -56910,10 +68440,11 @@ module.exports = class gemini extends Exchange {
const response = await this.publicGetV1Symbols (params);
const result = [];
for (let i = 0; i < response.length; i++) {
- const id = response[i];
- const market = id;
- const baseId = id.slice (0, 3);
- const quoteId = id.slice (3, 6);
+ const marketId = response[i];
+ const market = marketId;
+ const idLength = marketId.length - 0;
+ const baseId = marketId.slice (0, idLength - 3);
+ const quoteId = marketId.slice (idLength - 3, idLength);
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
@@ -56922,7 +68453,7 @@ module.exports = class gemini extends Exchange {
'price': undefined,
};
result.push ({
- 'id': id,
+ 'id': marketId,
'info': market,
'symbol': symbol,
'base': base,
@@ -56963,42 +68494,229 @@ module.exports = class gemini extends Exchange {
return this.parseOrderBook (response, undefined, 'bids', 'asks', 'price', 'amount');
}
- async fetchTicker (symbol, params = {}) {
+ async fetchTickerV1 (symbol, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
- const ticker = await this.publicGetV1PubtickerSymbol (this.extend (request, params));
- const timestamp = this.safeInteger (ticker['volume'], 'timestamp');
- const baseCurrency = market['base']; // unified structures are guaranteed to have unified fields
- const quoteCurrency = market['quote']; // so we don't need safe-methods for unified structures
- const last = this.safeFloat (ticker, 'last');
+ const response = await this.publicGetV1PubtickerSymbol (this.extend (request, params));
+ //
+ // {
+ // "bid":"9117.95",
+ // "ask":"9117.96",
+ // "volume":{
+ // "BTC":"1615.46861748",
+ // "USD":"14727307.57545006088",
+ // "timestamp":1594982700000
+ // },
+ // "last":"9115.23"
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ async fetchTickerV2 (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this.publicGetV2TickerSymbol (this.extend (request, params));
+ //
+ // {
+ // "symbol":"BTCUSD",
+ // "open":"9080.58",
+ // "high":"9184.53",
+ // "low":"9063.56",
+ // "close":"9116.08",
+ // // Hourly prices descending for past 24 hours
+ // "changes":["9117.33","9105.69","9106.23","9120.35","9098.57","9114.53","9113.55","9128.01","9113.63","9133.49","9133.49","9137.75","9126.73","9103.91","9119.33","9123.04","9124.44","9117.57","9114.22","9102.33","9076.67","9074.72","9074.97","9092.05"],
+ // "bid":"9115.86",
+ // "ask":"9115.87"
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ async fetchTickerV1AndV2 (symbol, params = {}) {
+ const tickerA = await this.fetchTickerV1 (symbol, params);
+ const tickerB = await this.fetchTickerV2 (symbol, params);
+ return this.deepExtend (tickerA, {
+ 'open': tickerB['open'],
+ 'high': tickerB['high'],
+ 'low': tickerB['low'],
+ 'change': tickerB['change'],
+ 'percentage': tickerB['percentage'],
+ 'average': tickerB['average'],
+ 'info': tickerB['info'],
+ });
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ const method = this.safeValue (this.options, 'fetchTickerMethod', 'fetchTickerV1');
+ return await this[method] (symbol, params);
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTickers
+ //
+ // {
+ // "pair": "BATUSD",
+ // "price": "0.20687",
+ // "percentChange24h": "0.0146"
+ // }
+ //
+ // fetchTickerV1
+ //
+ // {
+ // "bid":"9117.95",
+ // "ask":"9117.96",
+ // "volume":{
+ // "BTC":"1615.46861748",
+ // "USD":"14727307.57545006088",
+ // "timestamp":1594982700000
+ // },
+ // "last":"9115.23"
+ // }
+ //
+ // fetchTickerV2
+ //
+ // {
+ // "symbol":"BTCUSD",
+ // "open":"9080.58",
+ // "high":"9184.53",
+ // "low":"9063.56",
+ // "close":"9116.08",
+ // // Hourly prices descending for past 24 hours
+ // "changes":["9117.33","9105.69","9106.23","9120.35","9098.57","9114.53","9113.55","9128.01","9113.63","9133.49","9133.49","9137.75","9126.73","9103.91","9119.33","9123.04","9124.44","9117.57","9114.22","9102.33","9076.67","9074.72","9074.97","9092.05"],
+ // "bid":"9115.86",
+ // "ask":"9115.87"
+ // }
+ //
+ const volume = this.safeValue (ticker, 'volume', {});
+ const timestamp = this.safeInteger (volume, 'timestamp');
+ let symbol = undefined;
+ const marketId = this.safeString (ticker, 'pair');
+ let baseId = undefined;
+ let quoteId = undefined;
+ let base = undefined;
+ let quote = undefined;
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const idLength = marketId.length - 0;
+ if (idLength === 7) {
+ baseId = marketId.slice (0, 4);
+ quoteId = marketId.slice (4, 7);
+ } else {
+ baseId = marketId.slice (0, 3);
+ quoteId = marketId.slice (3, 6);
+ }
+ base = this.safeCurrencyCode (baseId);
+ quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ baseId = market['baseId'].toUpperCase ();
+ quoteId = market['quoteId'].toUpperCase ();
+ base = market['base'];
+ quote = market['quote'];
+ }
+ const price = this.safeFloat (ticker, 'price');
+ const last = this.safeFloat2 (ticker, 'last', 'close', price);
+ let percentage = this.safeFloat (ticker, 'percentChange24h');
+ let change = undefined;
+ let open = this.safeFloat (ticker, 'open');
+ let average = undefined;
+ if (last !== undefined) {
+ if (open !== undefined) {
+ change = last - open;
+ if (open !== 0) {
+ percentage = change / open * 100;
+ }
+ average = this.sum (last, open) / 2;
+ } else if (percentage !== undefined) {
+ change = last * percentage;
+ if (open === undefined) {
+ open = last - change;
+ }
+ average = this.sum (last, open) / 2;
+ }
+ }
+ const baseVolume = this.safeFloat (volume, baseId);
+ const quoteVolume = this.safeFloat (volume, quoteId);
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'high': undefined,
- 'low': undefined,
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
'bid': this.safeFloat (ticker, 'bid'),
'bidVolume': undefined,
'ask': this.safeFloat (ticker, 'ask'),
'askVolume': undefined,
- 'vwap': undefined,
- 'open': undefined,
+ 'vwap': vwap,
+ 'open': open,
'close': last,
'last': last,
- 'previousClose': undefined,
- 'change': undefined,
- 'percentage': undefined,
- 'average': undefined,
- 'baseVolume': this.safeFloat (ticker['volume'], baseCurrency),
- 'quoteVolume': this.safeFloat (ticker['volume'], quoteCurrency),
+ 'previousClose': undefined, // previous day close
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
'info': ticker,
};
}
+ parseTickers (tickers, symbols = undefined) {
+ const result = [];
+ for (let i = 0; i < tickers.length; i++) {
+ result.push (this.parseTicker (tickers[i]));
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetV1Pricefeed (params);
+ //
+ // [
+ // {
+ // "pair": "BATUSD",
+ // "price": "0.20687",
+ // "percentChange24h": "0.0146"
+ // },
+ // {
+ // "pair": "LINKETH",
+ // "price": "0.018",
+ // "percentChange24h": "0.0000"
+ // },
+ // ]
+ //
+ return this.parseTickers (response, symbols);
+ }
+
parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades
+ //
+ // {
+ // "timestamp":1601617445,
+ // "timestampms":1601617445144,
+ // "tid":14122489752,
+ // "price":"0.46476",
+ // "amount":"28.407209",
+ // "exchange":"gemini",
+ // "type":"buy"
+ // }
+ //
const timestamp = this.safeInteger (trade, 'timestampms');
const id = this.safeString (trade, 'tid');
const orderId = this.safeString (trade, 'order_id');
@@ -57018,10 +68736,7 @@ module.exports = class gemini extends Exchange {
}
const type = undefined;
const side = this.safeStringLower (trade, 'type');
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (undefined, market);
return {
'id': id,
'order': orderId,
@@ -57046,6 +68761,19 @@ module.exports = class gemini extends Exchange {
'symbol': market['id'],
};
const response = await this.publicGetV1TradesSymbol (this.extend (request, params));
+ //
+ // [
+ // {
+ // "timestamp":1601617445,
+ // "timestampms":1601617445144,
+ // "tid":14122489752,
+ // "price":"0.46476",
+ // "amount":"28.407209",
+ // "exchange":"gemini",
+ // "type":"buy"
+ // },
+ // ]
+ //
return this.parseTrades (response, market, since, limit);
}
@@ -57094,16 +68822,8 @@ module.exports = class gemini extends Exchange {
type = order['type'];
}
const fee = undefined;
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
const id = this.safeString (order, 'order_id');
const side = this.safeStringLower (order, 'side');
const clientOrderId = this.safeString (order, 'client_order_id');
@@ -57117,8 +68837,10 @@ module.exports = class gemini extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'average': average,
'cost': cost,
'amount': amount,
@@ -57141,12 +68863,11 @@ module.exports = class gemini extends Exchange {
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privatePostV1Orders (params);
- let orders = this.parseOrders (response, undefined, since, limit);
+ let market = undefined;
if (symbol !== undefined) {
- const market = this.market (symbol); // throws on non-existent symbol
- orders = this.filterBySymbol (orders, market['symbol']);
+ market = this.market (symbol); // throws on non-existent symbol
}
- return orders;
+ return this.parseOrders (response, market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
@@ -57277,7 +68998,7 @@ module.exports = class gemini extends Exchange {
'nonce': nonce,
}, query);
let payload = this.json (request);
- payload = this.stringToBase64 (this.encode (payload));
+ payload = this.stringToBase64 (payload);
const signature = this.hmac (payload, this.encode (this.secret), 'sha384');
headers = {
'Content-Type': 'text/plain',
@@ -57346,11 +69067,18 @@ module.exports = class gemini extends Exchange {
'symbol': market['id'],
};
const response = await this.publicGetV2CandlesSymbolTimeframe (this.extend (request, params));
+ //
+ // [
+ // [1591515000000,0.02509,0.02509,0.02509,0.02509,0],
+ // [1591514700000,0.02503,0.02509,0.02503,0.02509,44.6405],
+ // [1591514400000,0.02503,0.02503,0.02503,0.02503,0],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
};
-},{"./base/Exchange":7,"./base/errors":9}],89:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],88:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -57370,27 +69098,32 @@ module.exports = class hbtc extends Exchange {
'rateLimit': 2000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchTime': true,
+ 'createOrder': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
'fetchBidAsk': true,
'fetchBidsAsks': true,
- 'fetchTickers': true,
- 'fetchTicker': true,
- 'fetchDepositAddress': false,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
'fetchClosedOrders': true,
- 'fetchTradingLimits': true,
+ 'fetchCurrencies': false,
+ 'fetchDepositAddress': false,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
'fetchMarkets': true,
'fetchMyTrades': true,
- 'withdraw': true,
- 'fetchCurrencies': false,
- 'fetchDeposits': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchTradingLimits': true,
'fetchWithdrawals': true,
- 'fetchAccounts': true,
- 'fetchLedger': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1m',
@@ -57530,8 +69263,8 @@ module.exports = class hbtc extends Exchange {
'trading': {
'tierBased': false,
'percentage': true,
- 'maker': 0.002, // MAKER费率
- 'taker': 0.002, // TAKER费率
+ 'maker': 0.001,
+ 'taker': 0.001,
},
},
'exceptions': {
@@ -58104,7 +69837,7 @@ module.exports = class hbtc extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// [
// 1587906000000, // open time
@@ -59012,14 +70745,8 @@ module.exports = class hbtc extends Exchange {
// "askQty": "9.00000000"
// }
//
- let symbol = undefined;
const marketId = this.safeString (ticker, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.safeInteger (ticker, 'time');
const open = this.safeFloat (ticker, 'openPrice');
const close = this.safeFloat (ticker, 'lastPrice');
@@ -59035,10 +70762,7 @@ module.exports = class hbtc extends Exchange {
}
const quoteVolume = this.safeFloat (ticker, 'quoteVolume');
const baseVolume = this.safeFloat (ticker, 'volume');
- let vwap = undefined;
- if (baseVolume !== undefined && quoteVolume !== undefined && baseVolume > 0) {
- vwap = quoteVolume / baseVolume;
- }
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -59224,16 +70948,8 @@ module.exports = class hbtc extends Exchange {
if (timestamp === undefined) {
timestamp = this.safeInteger (order, 'transactTime');
}
- let symbol = undefined;
- if (market === undefined) {
- let marketId = this.safeString (order, 'symbol');
- if (marketId !== undefined) {
- marketId = marketId.toUpperCase ();
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
let type = this.safeStringLower (order, 'type');
const side = this.safeStringLower (order, 'side');
let price = this.safeFloat (order, 'price');
@@ -59270,9 +70986,8 @@ module.exports = class hbtc extends Exchange {
average = undefined;
}
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const timeInForce = this.safeString (order, 'timeInForce');
+ const stopPrice = this.safeFloat (order, 'stopPrice');
const result = {
'info': order,
'id': id,
@@ -59282,8 +70997,10 @@ module.exports = class hbtc extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'average': average,
'cost': cost,
'amount': amount,
@@ -59371,14 +71088,15 @@ module.exports = class hbtc extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],90:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],89:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
const { BadSymbol, PermissionDenied, ExchangeError, ExchangeNotAvailable, OrderNotFound, InsufficientFunds, InvalidOrder, RequestTimeout, AuthenticationError } = require ('./base/errors');
-const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number');
+const { TRUNCATE, DECIMAL_PLACES, TICK_SIZE } = require ('./base/functions/number');
+
// ---------------------------------------------------------------------------
module.exports = class hitbtc extends Exchange {
@@ -59391,24 +71109,32 @@ module.exports = class hitbtc extends Exchange {
'version': '2',
'pro': true,
'has': {
- 'createDepositAddress': true,
- 'fetchDepositAddress': true,
+ 'cancelOrder': true,
'CORS': false,
+ 'createDepositAddress': true,
+ 'createOrder': true,
'editOrder': true,
- 'fetchCurrencies': true,
- 'fetchOHLCV': true,
- 'fetchTickers': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchMyTrades': true,
- 'withdraw': true,
- 'fetchOrderTrades': false, // not implemented yet
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
'fetchDeposits': false,
- 'fetchWithdrawals': false,
- 'fetchTransactions': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrder': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
+ 'fetchTransactions': true,
+ 'fetchWithdrawals': false,
+ 'withdraw': true,
},
'timeframes': {
'1m': 'M1',
@@ -59448,46 +71174,61 @@ module.exports = class hitbtc extends Exchange {
'currency/{currency}', // Get currency info
'ticker', // Ticker list for all symbols
'ticker/{symbol}', // Ticker for symbol
+ 'trades',
'trades/{symbol}', // Trades
+ 'orderbook',
'orderbook/{symbol}', // Orderbook
+ 'candles',
'candles/{symbol}', // Candles
],
},
'private': {
'get': [
+ 'trading/balance', // Get trading balance
'order', // List your current open orders
'order/{clientOrderId}', // Get a single order by clientOrderId
- 'trading/balance', // Get trading balance
'trading/fee/all', // Get trading fee rate
'trading/fee/{symbol}', // Get trading fee rate
- 'history/trades', // Get historical trades
'history/order', // Get historical orders
- 'history/order/{id}/trades', // Get historical trades by specified order
+ 'history/trades', // Get historical trades
+ 'history/order/{orderId}/trades', // Get historical trades by specified order
'account/balance', // Get main acccount balance
+ 'account/crypto/address/{currency}', // Get deposit crypro address
+ 'account/crypto/is-mine/{address}',
'account/transactions', // Get account transactions
'account/transactions/{id}', // Get account transaction by id
- 'account/crypto/address/{currency}', // Get deposit crypro address
+ 'sub-acc',
+ 'sub-acc/acl',
+ 'sub-acc/balance/{subAccountUserID}',
+ 'sub-acc/deposit-address/{subAccountUserId}/{currency}',
],
'post': [
'order', // Create new order
- 'account/crypto/withdraw', // Withdraw crypro
'account/crypto/address/{currency}', // Create new deposit crypro address
+ 'account/crypto/withdraw', // Withdraw crypro
+ 'account/crypto/transfer-convert',
'account/transfer', // Transfer amount to trading
+ 'sub-acc/freeze',
+ 'sub-acc/activate',
+ 'sub-acc/transfer',
],
'put': [
'order/{clientOrderId}', // Create new order
'account/crypto/withdraw/{id}', // Commit withdraw crypro
+ 'sub-acc/acl/{subAccountUserId}',
],
'delete': [
'order', // Cancel all open orders
'order/{clientOrderId}', // Cancel order
'account/crypto/withdraw/{id}', // Rollback withdraw crypro
],
+ // outdated?
'patch': [
'order/{clientOrderId}', // Cancel Replace order
],
},
},
+ 'precisionMode': TICK_SIZE,
'fees': {
'trading': {
'tierBased': false,
@@ -59495,444 +71236,24 @@ module.exports = class hitbtc extends Exchange {
'maker': 0.1 / 100,
'taker': 0.2 / 100,
},
- 'funding': {
- 'tierBased': false,
- 'percentage': false,
- 'withdraw': {
- 'BTC': 0.001,
- 'BCC': 0.0018,
- 'ETH': 0.00958,
- 'BCH': 0.0018,
- 'USDT': 100,
- 'DASH': 0.03,
- 'BTG': 0.0005,
- 'XRP': 0.509,
- 'LTC': 0.003,
- 'ZEC': 0.0001,
- 'XMR': 0.09,
- '1ST': 0.84,
- 'ADX': 5.7,
- 'AE': 6.7,
- 'AEON': 0.01006,
- 'AIR': 565,
- 'AMM': 14,
- 'AMP': 342,
- 'ANT': 6.7,
- 'ARDR': 1,
- 'ARN': 18.5,
- 'ART': 26,
- 'ATB': 0.0004,
- 'ATL': 27,
- 'ATM': 504,
- 'ATS': 860,
- 'AVT': 1.9,
- 'BAS': 113,
- 'BCN': 0.1,
- 'BET': 124,
- 'BKB': 46,
- 'BMC': 32,
- 'BMT': 100,
- 'BNT': 2.57,
- 'BQX': 4.7,
- 'BTCA': 351.21,
- 'BTM': 40,
- 'BTX': 0.04,
- 'BUS': 0.004,
- 'CAPP': 97,
- 'CCT': 6,
- 'CDT': 100,
- 'CDX': 30,
- 'CFI': 61,
- 'CL': 13.85,
- 'CLD': 0.88,
- 'CND': 574,
- 'CNX': 0.04,
- 'COSS': 65,
- 'CPAY': 5.487,
- 'CSNO': 16,
- 'CTR': 15,
- 'CTX': 146,
- 'CVC': 8.46,
- 'DATA': 12.949,
- 'DBIX': 0.0168,
- 'DCN': 1280,
- 'DCT': 0.02,
- 'DDF': 342,
- 'DENT': 1000,
- 'DGB': 0.4,
- 'DGD': 0.01,
- 'DICE': 0.32,
- 'DLT': 0.26,
- 'DNT': 0.21,
- 'DOGE': 2,
- 'DOV': 34,
- 'DRPU': 24,
- 'DRT': 240,
- 'DSH': 0.017,
- 'EBET': 84,
- 'EBTC': 20,
- 'EBTCOLD': 6.6,
- 'ECAT': 14,
- 'EDG': 2,
- 'EDO': 2.9,
- 'EKO': 1136.36,
- 'ELE': 0.00172,
- 'ELM': 0.004,
- 'EMC': 0.03,
- 'MGO': 14,
- 'ENJ': 163,
- 'EOS': 1.5,
- 'ERO': 34,
- 'ETBS': 15,
- 'ETC': 0.002,
- 'ETP': 0.004,
- 'EVX': 5.4,
- 'EXN': 456,
- 'FCN': 0.000005,
- 'FRD': 65,
- 'FUEL': 123.00105,
- 'FUN': 202.9598309,
- 'FYN': 1.849,
- 'FYP': 66.13,
- 'GAME': 0.004,
- 'GNO': 0.0034,
- 'GUP': 4,
- 'GVT': 1.2,
- 'HSR': 0.04,
- 'HAC': 144,
- 'HDG': 7,
- 'HGT': 1082,
- 'HPC': 0.4,
- 'HVN': 120,
- 'ICN': 0.55,
- 'ICO': 34,
- 'ICOS': 0.35,
- 'IND': 76,
- 'INDI': 790,
- 'ITS': 15.0012,
- 'IXT': 11,
- 'KBR': 143,
- 'KICK': 112,
- 'KMD': 4,
- 'LA': 41,
- 'LEND': 388,
- 'LAT': 1.44,
- 'LIFE': 13000,
- 'LRC': 27,
- 'LSK': 0.3,
- 'LOC': 11.076,
- 'LUN': 0.34,
- 'MAID': 5,
- 'MANA': 143,
- 'MCAP': 5.44,
- 'MIPS': 43,
- 'MNE': 1.33,
- 'MSP': 121,
- 'MCO': 0.357,
- 'MTH': 92,
- 'MYB': 3.9,
- 'NDC': 165,
- 'NEBL': 0.04,
- 'NET': 3.96,
- 'NTO': 998,
- 'NGC': 2.368,
- 'NXC': 13.39,
- 'NXT': 3,
- 'OAX': 15,
- 'ODN': 0.004,
- 'OMG': 2,
- 'OPT': 335,
- 'ORME': 2.8,
- 'OTN': 0.57,
- 'PAY': 3.1,
- 'PIX': 96,
- 'PLBT': 0.33,
- 'PLR': 114,
- 'PLU': 0.87,
- 'POE': 784,
- 'POLL': 3.5,
- 'PPT': 2,
- 'PRE': 32,
- 'PRG': 39,
- 'PRO': 41,
- 'PRS': 60,
- 'PTOY': 0.5,
- 'QAU': 63,
- 'QCN': 0.03,
- 'QTUM': 0.04,
- 'QVT': 64,
- 'REP': 0.02,
- 'RKC': 15,
- 'RLC': 1.21,
- 'RVT': 14,
- 'SC': 30,
- 'SAN': 2.24,
- 'SBD': 0.03,
- 'SCL': 2.6,
- 'SISA': 1640,
- 'SKIN': 407,
- 'SWFTC': 352.94,
- 'SMART': 0.4,
- 'SMS': 0.0375,
- 'SNC': 36,
- 'SNGLS': 4,
- 'SNM': 48,
- 'SNT': 233,
- 'STAR': 0.144,
- 'STORM': 153.19,
- 'STEEM': 0.01,
- 'STRAT': 0.01,
- 'SPF': 14.4,
- 'STU': 14,
- 'STX': 11,
- 'SUB': 17,
- 'SUR': 3,
- 'SWT': 0.51,
- 'TAAS': 0.91,
- 'TBT': 2.37,
- 'TFL': 15,
- 'TIME': 0.03,
- 'TIX': 7.1,
- 'TKN': 1,
- 'TGT': 173,
- 'TKR': 84,
- 'TNT': 90,
- 'TRST': 1.6,
- 'TRX': 270,
- 'UET': 480,
- 'UGT': 15,
- 'UTT': 3,
- 'VEN': 14,
- 'VERI': 0.037,
- 'VIB': 50,
- 'VIBE': 145,
- 'VOISE': 618,
- 'WEALTH': 0.0168,
- 'WINGS': 2.4,
- 'WTC': 0.75,
- 'WRC': 48,
- 'XAUR': 3.23,
- 'XDN': 0.01,
- 'XEM': 15,
- 'XUC': 0.9,
- 'YOYOW': 140,
- 'ZAP': 24,
- 'ZRX': 23,
- 'ZSC': 191,
- },
- 'deposit': {
- 'BTC': 0,
- 'ETH': 0,
- 'BCH': 0,
- 'USDT': 0,
- 'BTG': 0,
- 'LTC': 0,
- 'ZEC': 0,
- 'XMR': 0,
- '1ST': 0,
- 'ADX': 0,
- 'AE': 0,
- 'AEON': 0,
- 'AIR': 0,
- 'AMP': 0,
- 'ANT': 0,
- 'ARDR': 0,
- 'ARN': 0,
- 'ART': 0,
- 'ATB': 0,
- 'ATL': 0,
- 'ATM': 0,
- 'ATS': 0,
- 'AVT': 0,
- 'BAS': 0,
- 'BCN': 0,
- 'BET': 0,
- 'BKB': 0,
- 'BMC': 0,
- 'BMT': 0,
- 'BNT': 0,
- 'BQX': 0,
- 'BTM': 0,
- 'BTX': 0,
- 'BUS': 0,
- 'CCT': 0,
- 'CDT': 0,
- 'CDX': 0,
- 'CFI': 0,
- 'CLD': 0,
- 'CND': 0,
- 'CNX': 0,
- 'COSS': 0,
- 'CSNO': 0,
- 'CTR': 0,
- 'CTX': 0,
- 'CVC': 0,
- 'DBIX': 0,
- 'DCN': 0,
- 'DCT': 0,
- 'DDF': 0,
- 'DENT': 0,
- 'DGB': 0,
- 'DGD': 0,
- 'DICE': 0,
- 'DLT': 0,
- 'DNT': 0,
- 'DOGE': 0,
- 'DOV': 0,
- 'DRPU': 0,
- 'DRT': 0,
- 'DSH': 0,
- 'EBET': 0,
- 'EBTC': 0,
- 'EBTCOLD': 0,
- 'ECAT': 0,
- 'EDG': 0,
- 'EDO': 0,
- 'ELE': 0,
- 'ELM': 0,
- 'EMC': 0,
- 'EMGO': 0,
- 'ENJ': 0,
- 'EOS': 0,
- 'ERO': 0,
- 'ETBS': 0,
- 'ETC': 0,
- 'ETP': 0,
- 'EVX': 0,
- 'EXN': 0,
- 'FRD': 0,
- 'FUEL': 0,
- 'FUN': 0,
- 'FYN': 0,
- 'FYP': 0,
- 'GNO': 0,
- 'GUP': 0,
- 'GVT': 0,
- 'HAC': 0,
- 'HDG': 0,
- 'HGT': 0,
- 'HPC': 0,
- 'HVN': 0,
- 'ICN': 0,
- 'ICO': 0,
- 'ICOS': 0,
- 'IND': 0,
- 'INDI': 0,
- 'ITS': 0,
- 'IXT': 0,
- 'KBR': 0,
- 'KICK': 0,
- 'LA': 0,
- 'LAT': 0,
- 'LIFE': 0,
- 'LRC': 0,
- 'LSK': 0,
- 'LUN': 0,
- 'MAID': 0,
- 'MANA': 0,
- 'MCAP': 0,
- 'MIPS': 0,
- 'MNE': 0,
- 'MSP': 0,
- 'MTH': 0,
- 'MYB': 0,
- 'NDC': 0,
- 'NEBL': 0,
- 'NET': 0,
- 'NTO': 0,
- 'NXC': 0,
- 'NXT': 0,
- 'OAX': 0,
- 'ODN': 0,
- 'OMG': 0,
- 'OPT': 0,
- 'ORME': 0,
- 'OTN': 0,
- 'PAY': 0,
- 'PIX': 0,
- 'PLBT': 0,
- 'PLR': 0,
- 'PLU': 0,
- 'POE': 0,
- 'POLL': 0,
- 'PPT': 0,
- 'PRE': 0,
- 'PRG': 0,
- 'PRO': 0,
- 'PRS': 0,
- 'PTOY': 0,
- 'QAU': 0,
- 'QCN': 0,
- 'QTUM': 0,
- 'QVT': 0,
- 'REP': 0,
- 'RKC': 0,
- 'RVT': 0,
- 'SAN': 0,
- 'SBD': 0,
- 'SCL': 0,
- 'SISA': 0,
- 'SKIN': 0,
- 'SMART': 0,
- 'SMS': 0,
- 'SNC': 0,
- 'SNGLS': 0,
- 'SNM': 0,
- 'SNT': 0,
- 'STEEM': 0,
- 'STRAT': 0,
- 'STU': 0,
- 'STX': 0,
- 'SUB': 0,
- 'SUR': 0,
- 'SWT': 0,
- 'TAAS': 0,
- 'TBT': 0,
- 'TFL': 0,
- 'TIME': 0,
- 'TIX': 0,
- 'TKN': 0,
- 'TKR': 0,
- 'TNT': 0,
- 'TRST': 0,
- 'TRX': 0,
- 'UET': 0,
- 'UGT': 0,
- 'VEN': 0,
- 'VERI': 0,
- 'VIB': 0,
- 'VIBE': 0,
- 'VOISE': 0,
- 'WEALTH': 0,
- 'WINGS': 0,
- 'WTC': 0,
- 'XAUR': 0,
- 'XDN': 0,
- 'XEM': 0,
- 'XUC': 0,
- 'YOYOW': 0,
- 'ZAP': 0,
- 'ZRX': 0,
- 'ZSC': 0,
- },
- },
},
'options': {
'defaultTimeInForce': 'FOK',
},
'commonCurrencies': {
+ 'BCC': 'BCC', // initial symbol for Bitcoin Cash, now inactive
'BET': 'DAO.Casino',
- 'CAT': 'BitClave',
+ 'BOX': 'BOX Token',
'CPT': 'Cryptaur', // conflict with CPT = Contents Protocol https://github.com/ccxt/ccxt/issues/4920 and https://github.com/ccxt/ccxt/issues/6081
- 'DRK': 'DASH',
- 'EMGO': 'MGO',
'GET': 'Themis',
'HSR': 'HC',
+ 'IQ': 'IQ.Cash',
'LNC': 'LinkerCoin',
'PLA': 'PlayChip',
- 'UNC': 'Unigame',
+ 'PNT': 'Penta',
+ 'TV': 'Tokenville',
'USD': 'USDT',
- 'XBT': 'BTC',
+ 'XPNT': 'PNT',
},
'exceptions': {
'504': RequestTimeout, // {"error":{"code":504,"message":"Gateway Timeout"}}
@@ -59943,8 +71264,9 @@ module.exports = class hitbtc extends Exchange {
'2011': InvalidOrder, // "Quantity too low"
'2020': InvalidOrder, // "Price not a valid number"
'20002': OrderNotFound, // canceling non-existent order
- '20001': InsufficientFunds,
+ '20001': InsufficientFunds, // {"error":{"code":20001,"message":"Insufficient funds","description":"Check that the funds are sufficient, given commissions"}}
},
+ 'orders': {}, // orders cache / emulation
});
}
@@ -59954,6 +71276,20 @@ module.exports = class hitbtc extends Exchange {
async fetchMarkets (params = {}) {
const response = await this.publicGetSymbol (params);
+ //
+ // [
+ // {
+ // "id":"BCNBTC",
+ // "baseCurrency":"BCN",
+ // "quoteCurrency":"BTC",
+ // "quantityIncrement":"100",
+ // "tickSize":"0.00000000001",
+ // "takeLiquidityRate":"0.002",
+ // "provideLiquidityRate":"0.001",
+ // "feeCurrency":"BTC"
+ // }
+ // ]
+ //
const result = [];
for (let i = 0; i < response.length; i++) {
const market = response[i];
@@ -59962,17 +71298,21 @@ module.exports = class hitbtc extends Exchange {
const quoteId = this.safeString (market, 'quoteCurrency');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
- const symbol = base + '/' + quote;
+ let symbol = base + '/' + quote;
+ // bequant fix
+ if (id.indexOf ('_') >= 0) {
+ symbol = id;
+ }
const lot = this.safeFloat (market, 'quantityIncrement');
const step = this.safeFloat (market, 'tickSize');
const precision = {
- 'price': this.precisionFromString (market['tickSize']),
- // FIXME: for lots > 1 the following line returns 0
- // 'amount': this.precisionFromString (market['quantityIncrement']),
- 'amount': -1 * parseInt (Math.log10 (lot)),
+ 'price': step,
+ 'amount': lot,
};
const taker = this.safeFloat (market, 'takeLiquidityRate');
const maker = this.safeFloat (market, 'provideLiquidityRate');
+ const feeCurrencyId = this.safeString (market, 'feeCurrency');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
result.push (this.extend (this.fees['trading'], {
'info': market,
'id': id,
@@ -59985,6 +71325,7 @@ module.exports = class hitbtc extends Exchange {
'taker': taker,
'maker': maker,
'precision': precision,
+ 'feeCurrency': feeCurrencyCode,
'limits': {
'amount': {
'min': lot,
@@ -60006,6 +71347,25 @@ module.exports = class hitbtc extends Exchange {
async fetchCurrencies (params = {}) {
const response = await this.publicGetCurrency (params);
+ //
+ // [
+ // {
+ // "id":"XPNT",
+ // "fullName":"pToken",
+ // "crypto":true,
+ // "payinEnabled":true,
+ // "payinPaymentId":false,
+ // "payinConfirmations":9,
+ // "payoutEnabled":true,
+ // "payoutIsPaymentId":false,
+ // "transferEnabled":true,
+ // "delisted":false,
+ // "payoutFee":"26.510000000000",
+ // "precisionPayout":18,
+ // "precisionTransfer":8
+ // }
+ // ]
+ //
const result = {};
for (let i = 0; i < response.length; i++) {
const currency = response[i];
@@ -60013,7 +71373,8 @@ module.exports = class hitbtc extends Exchange {
// todo: will need to rethink the fees
// to add support for multiple withdrawal/deposit methods and
// differentiated fees for each particular method
- const precision = 8; // default precision, todo: fix "magic constants"
+ const decimals = this.safeInteger (currency, 'precisionTransfer', 8);
+ const precision = 1 / Math.pow (10, decimals);
const code = this.safeCurrencyCode (id);
const payin = this.safeValue (currency, 'payinEnabled');
const payout = this.safeValue (currency, 'payoutEnabled');
@@ -60043,12 +71404,12 @@ module.exports = class hitbtc extends Exchange {
'precision': precision,
'limits': {
'amount': {
- 'min': Math.pow (10, -precision),
- 'max': Math.pow (10, precision),
+ 'min': 1 / Math.pow (10, decimals),
+ 'max': Math.pow (10, decimals),
},
'price': {
- 'min': Math.pow (10, -precision),
- 'max': Math.pow (10, precision),
+ 'min': 1 / Math.pow (10, decimals),
+ 'max': Math.pow (10, decimals),
},
'cost': {
'min': undefined,
@@ -60103,7 +71464,18 @@ module.exports = class hitbtc extends Exchange {
return this.parseBalance (result);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "timestamp":"2015-08-20T19:01:00.000Z",
+ // "open":"0.006",
+ // "close":"0.006",
+ // "min":"0.006",
+ // "max":"0.006",
+ // "volume":"0.003",
+ // "volumeQuote":"0.000018"
+ // }
+ //
return [
this.parse8601 (this.safeString (ohlcv, 'timestamp')),
this.safeFloat (ohlcv, 'open'),
@@ -60128,6 +71500,13 @@ module.exports = class hitbtc extends Exchange {
request['limit'] = limit;
}
const response = await this.publicGetCandlesSymbol (this.extend (request, params));
+ //
+ // [
+ // {"timestamp":"2015-08-20T19:01:00.000Z","open":"0.006","close":"0.006","min":"0.006","max":"0.006","volume":"0.003","volumeQuote":"0.000018"},
+ // {"timestamp":"2015-08-20T19:03:00.000Z","open":"0.006","close":"0.006","min":"0.006","max":"0.006","volume":"0.013","volumeQuote":"0.000078"},
+ // {"timestamp":"2015-08-20T19:06:00.000Z","open":"0.0055","close":"0.005","min":"0.005","max":"0.0055","volume":"0.003","volumeQuote":"0.0000155"},
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -60163,14 +71542,7 @@ module.exports = class hitbtc extends Exchange {
percentage = change / open * 100;
}
}
- let vwap = undefined;
- if (quoteVolume !== undefined) {
- if (baseVolume !== undefined) {
- if (baseVolume > 0) {
- vwap = quoteVolume / baseVolume;
- }
- }
- }
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -60202,17 +71574,11 @@ module.exports = class hitbtc extends Exchange {
for (let i = 0; i < response.length; i++) {
const ticker = response[i];
const marketId = this.safeString (ticker, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- const market = this.markets_by_id[marketId];
- const symbol = market['symbol'];
- result[symbol] = this.parseTicker (ticker, market);
- } else {
- result[marketId] = this.parseTicker (ticker);
- }
- }
+ const market = this.safeMarket (marketId);
+ const symbol = market['symbol'];
+ result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -60229,7 +71595,6 @@ module.exports = class hitbtc extends Exchange {
}
parseTrade (trade, market = undefined) {
- //
// createMarketOrder
//
// { fee: "0.0004644",
@@ -60238,36 +71603,39 @@ module.exports = class hitbtc extends Exchange {
// quantity: "1",
// timestamp: "2018-10-25T16:41:44.780Z" }
//
- // fetchTrades ...
+ // fetchTrades
//
- // fetchMyTrades ...
+ // { id: 974786185,
+ // price: '0.032462',
+ // quantity: '0.3673',
+ // side: 'buy',
+ // timestamp: '2020-10-16T12:57:39.846Z' }
//
+ // fetchMyTrades
+ //
+ // { id: 277210397,
+ // clientOrderId: '6e102f3e7f3f4e04aeeb1cdc95592f1a',
+ // orderId: 28102855393,
+ // symbol: 'ETHBTC',
+ // side: 'sell',
+ // quantity: '0.002',
+ // price: '0.073365',
+ // fee: '0.000000147',
+ // timestamp: '2018-04-28T18:39:55.345Z' }
const timestamp = this.parse8601 (trade['timestamp']);
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
let fee = undefined;
const feeCost = this.safeFloat (trade, 'fee');
if (feeCost !== undefined) {
- const feeCurrency = market ? market['quote'] : undefined;
+ const feeCurrencyCode = market ? market['feeCurrency'] : undefined;
fee = {
'cost': feeCost,
- 'currency': feeCurrency,
+ 'currency': feeCurrencyCode,
};
}
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
const orderId = this.safeString (trade, 'clientOrderId');
@@ -60439,7 +71807,7 @@ module.exports = class hitbtc extends Exchange {
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
// their max accepted length is 32 characters
@@ -60465,14 +71833,12 @@ module.exports = class hitbtc extends Exchange {
if (order['status'] === 'rejected') {
throw new InvalidOrder (this.id + ' order was rejected by the exchange ' + this.json (order));
}
- const id = order['id'];
- this.orders[id] = order;
return order;
}
async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
await this.loadMarkets ();
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
// their max accepted length is 32 characters
@@ -60491,14 +71857,12 @@ module.exports = class hitbtc extends Exchange {
request['price'] = this.priceToPrecision (symbol, price);
}
const response = await this.privatePatchOrderClientOrderId (this.extend (request, params));
- const order = this.parseOrder (response);
- this.orders[order['id']] = order;
- return order;
+ return this.parseOrder (response);
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
const request = {
@@ -60544,34 +71908,17 @@ module.exports = class hitbtc extends Exchange {
const created = this.parse8601 (this.safeString (order, 'createdAt'));
const updated = this.parse8601 (this.safeString (order, 'updatedAt'));
const marketId = this.safeString (order, 'symbol');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['id'];
- }
- }
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
const amount = this.safeFloat (order, 'quantity');
const filled = this.safeFloat (order, 'cumQuantity');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
const id = this.safeString (order, 'clientOrderId');
const clientOrderId = id;
let price = this.safeFloat (order, 'price');
- if (price === undefined) {
- if (id in this.orders) {
- price = this.orders[id]['price'];
- }
- }
let remaining = undefined;
let cost = undefined;
if (amount !== undefined) {
@@ -60619,6 +71966,7 @@ module.exports = class hitbtc extends Exchange {
};
}
}
+ const timeInForce = this.safeString (order, 'timeInForce');
return {
'id': id,
'clientOrderId': clientOrderId, // https://github.com/ccxt/ccxt/issues/5674
@@ -60628,8 +71976,10 @@ module.exports = class hitbtc extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'average': average,
'amount': amount,
'cost': cost,
@@ -60643,7 +71993,7 @@ module.exports = class hitbtc extends Exchange {
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
const request = {
@@ -60659,7 +72009,7 @@ module.exports = class hitbtc extends Exchange {
async fetchOpenOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
const request = {
@@ -60770,9 +72120,9 @@ module.exports = class hitbtc extends Exchange {
market = this.market (symbol);
}
const request = {
- 'id': id,
+ 'orderId': id,
};
- const response = await this.privateGetHistoryOrderIdTrades (this.extend (request, params));
+ const response = await this.privateGetHistoryOrderOrderIdTrades (this.extend (request, params));
const numOrders = response.length;
if (numOrders > 0) {
return this.parseTrades (response, market, since, limit);
@@ -60899,7 +72249,7 @@ module.exports = class hitbtc extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],91:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],90:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -61175,16 +72525,7 @@ module.exports = class hollaex extends Exchange {
for (let i = 0; i < marketIds.length; i++) {
const marketId = marketIds[i];
const orderbook = response[marketId];
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- const market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ const symbol = this.safeSymbol (marketId, undefined, '-');
const timestamp = this.parse8601 (this.safeString (orderbook, 'timestamp'));
result[symbol] = this.parseOrderBook (response[marketId], timestamp);
}
@@ -61270,18 +72611,9 @@ module.exports = class hollaex extends Exchange {
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const ticker = response[key];
- let symbol = key;
- let market = undefined;
const marketId = this.safeString (ticker, 'symbol', key);
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ const market = this.safeMarket (marketId, undefined, '-');
+ const symbol = market['symbol'];
result[symbol] = this.parseTicker (ticker, market);
}
return this.filterByArray (result, 'symbol', symbols);
@@ -61314,22 +72646,8 @@ module.exports = class hollaex extends Exchange {
// "symbol": "bch-usdt"
// }
//
- let symbol = undefined;
const marketId = this.safeString (ticker, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.parse8601 (this.safeString2 (ticker, 'time', 'timestamp'));
const close = this.safeFloat (ticker, 'close');
const result = {
@@ -61377,7 +72695,7 @@ module.exports = class hollaex extends Exchange {
// ]
// }
//
- const trades = await this.safeValue (response, market['id'], []);
+ const trades = this.safeValue (response, market['id'], []);
return this.parseTrades (trades, market, since, limit);
}
@@ -61403,23 +72721,9 @@ module.exports = class hollaex extends Exchange {
// "fee": 0.1
// }
//
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- let quote = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ market = this.safeMarket (marketId, market, '-');
+ const symbol = market['symbol'];
const datetime = this.safeString (trade, 'timestamp');
const timestamp = this.parse8601 (datetime);
const side = this.safeString (trade, 'side');
@@ -61434,13 +72738,14 @@ module.exports = class hollaex extends Exchange {
const feeCost = this.safeFloat (trade, 'fee');
let fee = undefined;
if (feeCost !== undefined) {
+ const quote = market['quote'];
const feeCurrencyCode = (market !== undefined) ? market['quote'] : quote;
fee = {
'cost': feeCost,
'currency': feeCurrencyCode,
};
}
- const result = {
+ return {
'info': trade,
'id': undefined,
'timestamp': timestamp,
@@ -61455,7 +72760,6 @@ module.exports = class hollaex extends Exchange {
'cost': cost,
'fee': fee,
};
- return result;
}
async fetchOHLCV (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
@@ -61620,22 +72924,8 @@ module.exports = class hollaex extends Exchange {
// "filled":0
// }
//
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const id = this.safeString (order, 'id');
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const type = this.safeString (order, 'type');
@@ -61663,8 +72953,10 @@ module.exports = class hollaex extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': filled,
'remaining': remaining,
@@ -62131,13 +73423,55 @@ module.exports = class hollaex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],92:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],91:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const huobipro = require ('./huobipro.js');
+const { NotSupported } = require ('./base/errors');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class huobijp extends huobipro {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'huobijp',
+ 'name': 'Huobi Japan',
+ 'countries': [ 'JP' ],
+ 'hostname': 'api-cloud.huobi.co.jp',
+ 'pro': true,
+ 'has': {
+ 'fetchDepositAddress': false,
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/85734211-85755480-b705-11ea-8b35-0b7f1db33a2f.jpg',
+ 'api': {
+ 'market': 'https://{hostname}',
+ 'public': 'https://{hostname}',
+ 'private': 'https://{hostname}',
+ },
+ 'www': 'https://www.huobi.co.jp',
+ 'referral': 'https://www.huobi.co.jp/register/?invite_code=znnq3',
+ 'doc': 'https://api-doc.huobi.co.jp',
+ 'fees': 'https://www.huobi.co.jp/support/fee',
+ },
+ });
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ throw new NotSupported (this.id + ' fetchDepositAddress not supported yet');
+ }
+};
+
+},{"./base/errors":7,"./huobipro.js":92}],92:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { AuthenticationError, ExchangeError, PermissionDenied, ExchangeNotAvailable, InvalidOrder, OrderNotFound, InsufficientFunds, ArgumentsRequired, BadSymbol, BadRequest, RequestTimeout } = require ('./base/errors');
+const { AuthenticationError, ExchangeError, PermissionDenied, ExchangeNotAvailable, OnMaintenance, InvalidOrder, OrderNotFound, InsufficientFunds, ArgumentsRequired, BadSymbol, BadRequest, RequestTimeout, NetworkError } = require ('./base/errors');
+const { TRUNCATE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -62155,20 +73489,27 @@ module.exports = class huobipro extends Exchange {
'hostname': 'api.huobi.pro', // api.testnet.huobi.pro
'pro': true,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchTickers': true,
- 'fetchDepositAddress': true,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchTradingLimits': true,
- 'fetchMyTrades': true,
- 'withdraw': true,
'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTradingLimits': true,
'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1min',
@@ -62196,10 +73537,10 @@ module.exports = class huobipro extends Exchange {
'v2Public': 'https://{hostname}',
'v2Private': 'https://{hostname}',
},
- 'www': 'https://www.huobi.pro',
- 'referral': 'https://www.huobi.co/en-us/topic/invited/?invite_code=rwrd3',
+ 'www': 'https://www.huobi.com',
+ 'referral': 'https://www.huobi.com/en-us/topic/invited/?invite_code=rwrd3',
'doc': 'https://huobiapi.github.io/docs/spot/v1/cn/',
- 'fees': 'https://www.huobi.pro/about/fee/',
+ 'fees': 'https://www.huobi.com/about/fee/',
},
'api': {
'v2Public': {
@@ -62209,12 +73550,29 @@ module.exports = class huobipro extends Exchange {
},
'v2Private': {
'get': [
+ 'account/ledger',
'account/withdraw/quota',
+ 'account/withdraw/address', // 提币地址查询(限母用户可用)
'account/deposit/address',
'reference/transact-fee-rate',
+ 'account/asset-valuation', // 获取账户资产估值
+ 'point/account', // 点卡余额查询
+ 'sub-user/user-list', // 获取子用户列表
+ 'sub-user/user-state', // 获取特定子用户的用户状态
+ 'sub-user/account-list', // 获取特定子用户的账户列表
+ 'sub-user/deposit-address', // 子用户充币地址查询
+ 'sub-user/query-deposit', // 子用户充币记录查询
+ 'user/api-key', // 母子用户API key信息查询
],
'post': [
- 'sub-user/management',
+ 'point/transfer', // 点卡划转
+ 'sub-user/management', // 冻结/解冻子用户
+ 'sub-user/creation', // 子用户创建
+ 'sub-user/tradable-market', // 设置子用户交易权限
+ 'sub-user/transferability', // 设置子用户资产转出权限
+ 'sub-user/api-key-generation', // 子用户API key创建
+ 'sub-user/api-key-modification', // 修改子用户API key
+ 'sub-user/api-key-deletion', // 删除子用户API key
],
},
'market': {
@@ -62244,6 +73602,7 @@ module.exports = class huobipro extends Exchange {
'account/accounts/{sub-uid}',
'account/history',
'cross-margin/loan-info',
+ 'margin/loan-info', // 查询借币币息率及额度
'fee/fee-rate/get',
'order/openOrders',
'order/orders',
@@ -62252,10 +73611,13 @@ module.exports = class huobipro extends Exchange {
'order/orders/getClientOrder',
'order/history', // 查询当前委托、历史委托
'order/matchresults', // 查询当前成交、历史成交
- 'dw/withdraw-virtual/addresses', // 查询虚拟币提现地址
+ 'dw/withdraw-virtual/addresses', // 查询虚拟币提现地址(Deprecated)
'query/deposit-withdraw',
+ 'margin/loan-info',
'margin/loan-orders', // 借贷订单
'margin/accounts/balance', // 借贷账户详情
+ 'cross-margin/loan-orders', // 查询借币订单
+ 'cross-margin/accounts/balance', // 借币账户详情
'points/actions',
'points/orders',
'subuser/aggregate-balance',
@@ -62263,6 +73625,7 @@ module.exports = class huobipro extends Exchange {
'stable-coin/quote',
],
'post': [
+ 'account/transfer', // 资产划转(该节点为母用户和子用户进行资产划转的通用接口。)
'futures/transfer',
'order/batch-orders',
'order/orders/place', // 创建并执行一个新订单 (一步下单, 推荐使用)
@@ -62275,12 +73638,16 @@ module.exports = class huobipro extends Exchange {
'dw/balance/transfer', // 资产划转
'dw/withdraw/api/create', // 申请提现虚拟币
'dw/withdraw-virtual/create', // 申请提现虚拟币
- 'dw/withdraw-virtual/{id}/place', // 确认申请虚拟币提现
+ 'dw/withdraw-virtual/{id}/place', // 确认申请虚拟币提现(Deprecated)
'dw/withdraw-virtual/{id}/cancel', // 申请取消提现虚拟币
'dw/transfer-in/margin', // 现货账户划入至借贷账户
'dw/transfer-out/margin', // 借贷账户划出至现货账户
'margin/orders', // 申请借贷
'margin/orders/{id}/repay', // 归还借贷
+ 'cross-margin/transfer-in', // 资产划转
+ 'cross-margin/transfer-out', // 资产划转
+ 'cross-margin/orders', // 申请借币
+ 'cross-margin/orders/{id}/repay', // 归还借币
'stable-coin/exchange',
'subuser/transfer',
],
@@ -62314,10 +73681,12 @@ module.exports = class huobipro extends Exchange {
'api-signature-check-failed': AuthenticationError,
'api-signature-not-valid': AuthenticationError, // {"status":"error","err-code":"api-signature-not-valid","err-msg":"Signature not valid: Incorrect Access key [Access key错误]","data":null}
'base-record-invalid': OrderNotFound, // https://github.com/ccxt/ccxt/issues/5750
+ 'base-symbol-trade-disabled': BadSymbol, // {"status":"error","err-code":"base-symbol-trade-disabled","err-msg":"Trading is disabled for this symbol","data":null}
+ 'base-symbol-error': BadSymbol, // {"status":"error","err-code":"base-symbol-error","err-msg":"The symbol is invalid","data":null}
+ 'system-maintenance': OnMaintenance, // {"status": "error", "err-code": "system-maintenance", "err-msg": "System is in maintenance!", "data": null}
// err-msg
'invalid symbol': BadSymbol, // {"ts":1568813334794,"status":"error","err-code":"invalid-parameter","err-msg":"invalid symbol"}
- 'invalid-parameter': BadRequest, // {"ts":1576210479343,"status":"error","err-code":"invalid-parameter","err-msg":"symbol trade not open now"}
- 'base-symbol-trade-disabled': BadSymbol, // {"status":"error","err-code":"base-symbol-trade-disabled","err-msg":"Trading is disabled for this symbol","data":null}
+ 'symbol trade not open now': BadSymbol, // {"ts":1576210479343,"status":"error","err-code":"invalid-parameter","err-msg":"symbol trade not open now"}
},
},
'options': {
@@ -62336,6 +73705,11 @@ module.exports = class huobipro extends Exchange {
// https://github.com/ccxt/ccxt/issues/2873
'GET': 'Themis', // conflict with GET (Guaranteed Entrance Token, GET Protocol)
'HOT': 'Hydro Protocol', // conflict with HOT (Holo) https://github.com/ccxt/ccxt/issues/4929
+ // https://github.com/ccxt/ccxt/issues/7399
+ // https://coinmarketcap.com/currencies/pnetwork/
+ // https://coinmarketcap.com/currencies/penta/markets/
+ // https://en.cryptonomist.ch/blog/eidoo/the-edo-to-pnt-upgrade-what-you-need-to-know-updated/
+ 'PNT': 'Penta',
},
});
}
@@ -62407,13 +73781,17 @@ module.exports = class huobipro extends Exchange {
};
}
+ costToPrecision (symbol, cost) {
+ return this.decimalToPrecision (cost, TRUNCATE, this.markets[symbol]['precision']['cost'], this.precisionMode);
+ }
+
async fetchMarkets (params = {}) {
const method = this.options['fetchMarketsMethod'];
const response = await this[method] (params);
const markets = this.safeValue (response, 'data');
const numMarkets = markets.length;
if (numMarkets < 1) {
- throw new ExchangeError (this.id + ' publicGetCommonSymbols returned empty response: ' + this.json (markets));
+ throw new NetworkError (this.id + ' publicGetCommonSymbols returned empty response: ' + this.json (markets));
}
const result = [];
for (let i = 0; i < markets.length; i++) {
@@ -62425,8 +73803,9 @@ module.exports = class huobipro extends Exchange {
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
const precision = {
- 'amount': market['amount-precision'],
- 'price': market['price-precision'],
+ 'amount': this.safeInteger (market, 'amount-precision'),
+ 'price': this.safeInteger (market, 'price-precision'),
+ 'cost': this.safeInteger (market, 'value-precision'),
};
const maker = (base === 'OMG') ? 0 : 0.2 / 100;
const taker = (base === 'OMG') ? 0 : 0.2 / 100;
@@ -62541,10 +73920,7 @@ module.exports = class huobipro extends Exchange {
}
const baseVolume = this.safeFloat (ticker, 'amount');
const quoteVolume = this.safeFloat (ticker, 'vol');
- let vwap = undefined;
- if (baseVolume !== undefined && quoteVolume !== undefined && baseVolume > 0) {
- vwap = quoteVolume / baseVolume;
- }
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -62600,7 +73976,7 @@ module.exports = class huobipro extends Exchange {
//
if ('tick' in response) {
if (!response['tick']) {
- throw new ExchangeError (this.id + ' fetchOrderBook() returned empty response: ' + this.json (response));
+ throw new BadSymbol (this.id + ' fetchOrderBook() returned empty response: ' + this.json (response));
}
const tick = this.safeValue (response, 'tick');
const timestamp = this.safeInteger (tick, 'ts', this.safeInteger (response, 'ts'));
@@ -62653,15 +74029,12 @@ module.exports = class huobipro extends Exchange {
const result = {};
for (let i = 0; i < tickers.length; i++) {
const marketId = this.safeString (tickers[i], 'symbol');
- const market = this.safeValue (this.markets_by_id, marketId);
- let symbol = marketId;
- if (market !== undefined) {
- symbol = market['symbol'];
- const ticker = this.parseTicker (tickers[i], market);
- ticker['timestamp'] = timestamp;
- ticker['datetime'] = this.iso8601 (timestamp);
- result[symbol] = ticker;
- }
+ const market = this.safeMarket (marketId);
+ const symbol = market['symbol'];
+ const ticker = this.parseTicker (tickers[i], market);
+ ticker['timestamp'] = timestamp;
+ ticker['datetime'] = this.iso8601 (timestamp);
+ result[symbol] = ticker;
}
return this.filterByArray (result, 'symbol', symbols);
}
@@ -62681,16 +74054,26 @@ module.exports = class huobipro extends Exchange {
//
// fetchMyTrades (private)
//
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (trade, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ // {
+ // 'symbol': 'swftcbtc',
+ // 'fee-currency': 'swftc',
+ // 'filled-fees': '0',
+ // 'source': 'spot-api',
+ // 'id': 83789509854000,
+ // 'type': 'buy-limit',
+ // 'order-id': 83711103204909,
+ // 'filled-points': '0.005826843283532154',
+ // 'fee-deduct-currency': 'ht',
+ // 'filled-amount': '45941.53',
+ // 'price': '0.0000001401',
+ // 'created-at': 1597933260729,
+ // 'match-id': 100087455560,
+ // 'role': 'maker',
+ // 'trade-id': 100050305348
+ // },
+ //
+ const marketId = this.safeString (trade, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.safeInteger2 (trade, 'ts', 'created-at');
const order = this.safeString (trade, 'order-id');
let side = this.safeString (trade, 'direction');
@@ -62713,7 +74096,7 @@ module.exports = class huobipro extends Exchange {
let feeCost = this.safeFloat (trade, 'filled-fees');
let feeCurrency = undefined;
if (market !== undefined) {
- feeCurrency = (side === 'buy') ? market['base'] : market['quote'];
+ feeCurrency = this.safeCurrencyCode (this.safeString (trade, 'fee-currency'));
}
const filledPoints = this.safeFloat (trade, 'filled-points');
if (filledPoints !== undefined) {
@@ -62813,7 +74196,19 @@ module.exports = class huobipro extends Exchange {
return this.filterBySymbolSinceLimit (result, symbol, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "amount":1.2082,
+ // "open":0.025096,
+ // "close":0.025095,
+ // "high":0.025096,
+ // "id":1591515300,
+ // "count":6,
+ // "low":0.025095,
+ // "vol":0.0303205097
+ // }
+ //
return [
this.safeTimestamp (ohlcv, 'id'),
this.safeFloat (ohlcv, 'open'),
@@ -62835,7 +74230,20 @@ module.exports = class huobipro extends Exchange {
request['size'] = limit;
}
const response = await this.marketGetHistoryKline (this.extend (request, params));
- return this.parseOHLCVs (response['data'], market, timeframe, since, limit);
+ //
+ // {
+ // "status":"ok",
+ // "ch":"market.ethbtc.kline.1min",
+ // "ts":1591515374371,
+ // "data":[
+ // {"amount":0.0,"open":0.025095,"close":0.025095,"high":0.025095,"id":1591515360,"count":0,"low":0.025095,"vol":0.0},
+ // {"amount":1.2082,"open":0.025096,"close":0.025095,"high":0.025096,"id":1591515300,"count":6,"low":0.025095,"vol":0.0303205097},
+ // {"amount":0.0648,"open":0.025096,"close":0.025096,"high":0.025096,"id":1591515240,"count":2,"low":0.025096,"vol":0.0016262208},
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async fetchAccounts (params = {}) {
@@ -63118,18 +74526,8 @@ module.exports = class huobipro extends Exchange {
type = orderType[1];
status = this.parseOrderStatus (this.safeString (order, 'state'));
}
- let symbol = undefined;
- if (market === undefined) {
- if ('symbol' in order) {
- if (order['symbol'] in this.markets_by_id) {
- const marketId = order['symbol'];
- market = this.markets_by_id[marketId];
- }
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.safeInteger (order, 'created-at');
let amount = this.safeFloat (order, 'amount');
const filled = this.safeFloat2 (order, 'filled-amount', 'field-amount'); // typo in their API, filled amount
@@ -63173,8 +74571,10 @@ module.exports = class huobipro extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'average': average,
'cost': cost,
'amount': amount,
@@ -63202,9 +74602,10 @@ module.exports = class huobipro extends Exchange {
} else {
// despite that cost = amount * price is in quote currency and should have quote precision
// the exchange API requires the cost supplied in 'amount' to be of base precision
- // more about it here: https://github.com/ccxt/ccxt/pull/4395
- // we use priceToPrecision instead of amountToPrecision here
- // because in this case the amount is in the quote currency
+ // more about it here:
+ // https://github.com/ccxt/ccxt/pull/4395
+ // https://github.com/ccxt/ccxt/issues/7611
+ // we use amountToPrecision here because the exchange requires cost in base precision
request['amount'] = this.costToPrecision (symbol, parseFloat (amount) * parseFloat (price));
}
} else {
@@ -63559,7 +74960,7 @@ module.exports = class huobipro extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],93:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],93:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -63582,7 +74983,6 @@ module.exports = class huobiru extends huobipro {
'market': 'https://{hostname}/api',
'public': 'https://{hostname}/api',
'private': 'https://{hostname}/api',
- 'zendesk': 'https://huobiglobal.zendesk.com/hc/en-us/articles',
},
'www': 'https://www.huobi.com.ru/ru-ru',
'referral': 'https://www.huobi.com.ru/invite?invite_code=esc74',
@@ -63612,20 +75012,24 @@ module.exports = class ice3x extends Exchange {
'rateLimit': 1000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchCurrencies': true,
- 'fetchTickers': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
- 'fetchMyTrades': true,
'fetchDepositAddress': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/38012176-11616c32-3269-11e8-9f05-e65cf885bb15.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87460809-1dd06c00-c616-11ea-98ad-7d5e1cb7fcdd.jpg',
'api': 'https://ice3x.com/api',
- 'www': [
- 'https://ice3x.com',
- 'https://ice3x.co.za',
- ],
+ 'www': 'https://ice3x.com', // 'https://ice3x.co.za',
'doc': 'https://ice3x.co.za/ice-cubed-bitcoin-exchange-api-documentation-1-june-2017',
'fees': [
'https://help.ice3.com/support/solutions/articles/11000033293-trading-fees',
@@ -63805,7 +75209,7 @@ module.exports = class ice3x extends Exchange {
result[symbol] = this.parseTicker (ticker, market);
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -63936,8 +75340,10 @@ module.exports = class ice3x extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
- 'side': this.safeStrin (order, 'type'),
+ 'timeInForce': undefined,
+ 'side': this.safeString (order, 'type'),
'price': price,
+ 'stopPrice': undefined,
'cost': undefined,
'amount': amount,
'filled': filled,
@@ -63969,8 +75375,6 @@ module.exports = class ice3x extends Exchange {
'remaining': amount,
'info': response,
}, market);
- const id = order['id'];
- this.orders[id] = order;
return order;
}
@@ -63987,15 +75391,21 @@ module.exports = class ice3x extends Exchange {
'order _id': id,
};
const response = await this.privatePostOrderInfo (this.extend (request, params));
- const order = this.safeValue (response['response'], 'entity');
+ const data = this.safeValue (response, 'response', {});
+ const order = this.safeValue (data, 'entity');
return this.parseOrder (order);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privatePostOrderList (params);
- const orders = this.safeValue (response['response'], 'entities');
- return this.parseOrders (orders, undefined, since, limit);
+ const data = this.safeValue (response, 'response', {});
+ const orders = this.safeValue (data, 'entities', []);
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ return this.parseOrders (orders, market, since, limit);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -64011,7 +75421,8 @@ module.exports = class ice3x extends Exchange {
request['date_from'] = parseInt (since / 1000);
}
const response = await this.privatePostTradeList (this.extend (request, params));
- const trades = this.safeValue (response['response'], 'entities');
+ const data = this.safeValue (response, 'response', {});
+ const trades = this.safeValue (data, 'entities', []);
return this.parseTrades (trades, market, since, limit);
}
@@ -64022,7 +75433,8 @@ module.exports = class ice3x extends Exchange {
'currency_id': currency['id'],
};
const response = await this.privatePostBalanceInfo (this.extend (request, params));
- const balance = this.safeValue (response['response'], 'entity');
+ const data = this.safeValue (response, 'response', {});
+ const balance = this.safeValue (data, 'entity', {});
const address = this.safeString (balance, 'address');
const status = address ? 'ok' : 'none';
return {
@@ -64077,13 +75489,14 @@ module.exports = class ice3x extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],95:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],95:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, AuthenticationError, InsufficientFunds, InvalidOrder } = require ('./base/errors');
+const { PAD_WITH_ZERO } = require ('./base/functions/number');
+const { InvalidOrder, InsufficientFunds, ExchangeError, ExchangeNotAvailable, DDoSProtection, BadRequest, NotSupported, InvalidAddress, AuthenticationError } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -64094,1082 +75507,1296 @@ module.exports = class idex extends Exchange {
'name': 'IDEX',
'countries': [ 'US' ],
'rateLimit': 1500,
+ 'version': 'v2',
'certified': true,
+ 'pro': true,
'requiresWeb3': true,
'has': {
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchCurrencies': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchClosedOrders': true,
+ 'fetchOrders': false,
+ 'fetchOrder': true,
'fetchOrderBook': true,
'fetchTicker': true,
'fetchTickers': true,
- 'fetchMarkets': true,
- 'fetchBalance': true,
- 'createOrder': true,
- 'cancelOrder': true,
- 'fetchOpenOrders': true,
- 'fetchTransactions': true,
'fetchTrades': true,
- 'fetchMyTrades': true,
+ 'fetchTransactions': false,
+ 'fetchDeposits': true,
+ 'fetchWithdrawals': true,
'withdraw': true,
- 'fetchOHLCV': false,
},
'timeframes': {
- '1m': 'M1',
- '3m': 'M3',
- '5m': 'M5',
- '15m': 'M15',
- '30m': 'M30', // default
- '1h': 'H1',
- '4h': 'H4',
- '1d': 'D1',
- '1w': 'D7',
- '1M': '1M',
+ '1m': '1m',
+ '5m': '5m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '6h': '6h',
+ '1d': '1d',
},
'urls': {
- 'test': 'https://api.idex.market',
- 'logo': 'https://user-images.githubusercontent.com/1294454/63693236-3415e380-c81c-11e9-8600-ba1634f1407d.jpg',
- 'api': 'https://api.idex.market',
- 'www': 'https://idex.market',
+ 'test': {
+ 'public': 'https://api-sandbox.idex.io',
+ 'private': 'https://api-sandbox.idex.io',
+ },
+ 'logo': 'https://user-images.githubusercontent.com/51840849/94481303-2f222100-01e0-11eb-97dd-bc14c5943a86.jpg',
+ 'api': {
+ 'public': 'https://api.idex.io',
+ 'private': 'https://api.idex.io',
+ },
+ 'www': 'https://idex.io',
'doc': [
- 'https://docs.idex.market/',
+ 'https://docs.idex.io/',
],
},
'api': {
'public': {
- 'post': [
- 'returnTicker',
- 'returnCurrenciesWithPairs', // undocumented
- 'returnCurrencies',
- 'return24Volume',
- 'returnBalances',
- 'returnCompleteBalances', // shows amount in orders as well as total
- 'returnDepositsWithdrawals',
- 'returnOpenOrders',
- 'returnOrderBook',
- 'returnOrderStatus',
- 'returnOrderTrades',
- 'returnTradeHistory',
- 'returnTradeHistoryMeta', // not documented
- 'returnContractAddress',
- 'returnNextNonce',
+ 'get': [
+ 'ping',
+ 'time',
+ 'exchange',
+ 'assets',
+ 'markets',
+ 'tickers',
+ 'candles',
+ 'trades',
+ 'orderbook',
+ 'wsToken',
],
},
'private': {
+ 'get': [
+ 'user',
+ 'wallets',
+ 'balances',
+ 'orders',
+ 'fills',
+ 'deposits',
+ 'withdrawals',
+ ],
'post': [
- 'order',
- 'cancel',
- 'trade',
- 'withdraw',
+ 'wallets',
+ 'orders',
+ 'orders/test',
+ 'withdrawals',
+ ],
+ 'delete': [
+ 'orders',
],
},
},
'options': {
- 'contractAddress': undefined, // 0x2a0c0DBEcC7E4D658f48E01e3fA353F44050c208
- 'orderNonce': undefined,
+ 'defaultTimeInForce': 'gtc',
+ 'defaultSelfTradePrevention': 'cn',
},
'exceptions': {
- 'Invalid order signature. Please try again.': AuthenticationError,
- 'You have insufficient funds to match this order. If you believe this is a mistake please refresh and try again.': InsufficientFunds,
- 'Order no longer available.': InvalidOrder,
+ 'INVALID_ORDER_QUANTITY': InvalidOrder,
+ 'INSUFFICIENT_FUNDS': InsufficientFunds,
+ 'SERVICE_UNAVAILABLE': ExchangeNotAvailable,
+ 'EXCEEDED_RATE_LIMIT': DDoSProtection,
+ 'INVALID_PARAMETER': BadRequest,
+ 'WALLET_NOT_ASSOCIATED': InvalidAddress,
+ 'INVALID_WALLET_SIGNATURE': AuthenticationError,
},
'requiredCredentials': {
'walletAddress': true,
'privateKey': true,
- 'apiKey': false,
- 'secret': false,
+ 'apiKey': true,
+ 'secret': true,
},
- 'commonCurrencies': {
- 'FT': 'Fabric Token',
- 'MT': 'Monarch',
- 'ONE': 'Menlo One',
- 'PLA': 'PlayChip',
- 'WAX': 'WAXP',
+ 'paddingMode': PAD_WITH_ZERO,
+ 'commonCurrencies': {},
+ 'requireCredentials': {
+ 'privateKey': true,
+ 'apiKey': true,
+ 'secret': true,
},
});
}
async fetchMarkets (params = {}) {
- // idex does not have an endpoint for markets
- // instead we generate the markets from the endpoint for currencies
- const request = {
- 'includeDelisted': true,
- };
- const markets = await this.publicPostReturnCurrenciesWithPairs (this.extend (request, params));
- const currenciesById = {};
- const currencies = markets['tokens'];
- for (let i = 0; i < currencies.length; i++) {
- const currency = currencies[i];
- currenciesById[currency['symbol']] = currency;
- }
+ // [
+ // {
+ // market: 'DIL-ETH',
+ // status: 'active',
+ // baseAsset: 'DIL',
+ // baseAssetPrecision: 8,
+ // quoteAsset: 'ETH',
+ // quoteAssetPrecision: 8
+ // }, ...
+ // ]
+ const response = await this.publicGetMarkets (params);
const result = [];
- const limits = {
- 'amount': {
- 'min': undefined,
- 'max': undefined,
- },
- 'price': {
- 'min': undefined,
- 'max': undefined,
- },
- 'cost': {
- 'min': undefined,
- 'max': undefined,
- },
- };
- const quotes = markets['pairs'];
- const keys = Object.keys (quotes);
- for (let i = 0; i < keys.length; i++) {
- const quoteId = keys[i];
- const bases = quotes[quoteId];
+ for (let i = 0; i < response.length; i++) {
+ const entry = response[i];
+ const marketId = this.safeString (entry, 'market');
+ const baseId = this.safeString (entry, 'baseAsset');
+ const quoteId = this.safeString (entry, 'quoteAsset');
+ const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
- const quoteCurrency = currenciesById[quoteId];
- for (let j = 0; j < bases.length; j++) {
- const baseId = bases[j];
- const id = quoteId + '_' + baseId;
- const base = this.safeCurrencyCode (baseId);
- const symbol = base + '/' + quote;
- const baseCurrency = currenciesById[baseId];
- const baseAddress = baseCurrency['address'];
- const quoteAddress = quoteCurrency['address'];
- const precision = {
- 'price': this.safeInteger (quoteCurrency, 'decimals'),
- 'amount': this.safeInteger (baseCurrency, 'decimals'),
- };
- result.push ({
- 'symbol': symbol,
- 'precision': precision,
- 'base': base,
- 'quote': quote,
- 'baseId': baseAddress,
- 'quoteId': quoteAddress,
- 'limits': limits,
- 'id': id,
- 'info': baseCurrency,
- 'tierBased': false,
- });
- }
+ const symbol = base + '/' + quote;
+ const basePrecision = this.safeInteger (entry, 'baseAssetPrecision');
+ const quotePrecision = this.safeInteger (entry, 'quoteAssetPrecision');
+ const status = this.safeString (entry, 'status');
+ const active = status === 'active';
+ const precision = {
+ 'amount': basePrecision,
+ 'price': quotePrecision,
+ };
+ result.push ({
+ 'symbol': symbol,
+ 'id': marketId,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'active': active,
+ 'info': entry,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': Math.pow (10, -precision['amount']),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ });
}
return result;
}
- parseTicker (ticker, market = undefined) {
- //
- // {
- // last: '0.0016550916',
- // high: 'N/A',
- // low: 'N/A',
- // lowestAsk: '0.0016743368',
- // highestBid: '0.001163726270773897',
- // percentChange: '0',
- // baseVolume: '0',
- // quoteVolume: '0'
- // }
- //
- let symbol = undefined;
- if (market) {
- symbol = market['symbol'];
- }
- const baseVolume = this.safeFloat (ticker, 'baseVolume');
- const quoteVolume = this.safeFloat (ticker, 'quoteVolume');
- const last = this.safeFloat (ticker, 'last');
- const percentage = this.safeFloat (ticker, 'percentChange');
- return {
- 'symbol': symbol,
- 'timestamp': undefined,
- 'datetime': undefined,
- 'high': this.safeFloat (ticker, 'high'),
- 'low': this.safeFloat (ticker, 'low'),
- 'bid': this.safeFloat (ticker, 'highestBid'),
- 'bidVolume': undefined,
- 'ask': this.safeFloat (ticker, 'lowestAsk'),
- 'askVolume': undefined,
- 'vwap': undefined,
- 'open': undefined,
- 'close': last,
- 'last': last,
- 'previousClose': undefined,
- 'change': undefined,
- 'percentage': percentage,
- 'average': undefined,
- 'baseVolume': quoteVolume,
- 'quoteVolume': baseVolume,
- 'info': ticker,
- };
- }
-
- async fetchTickers (symbols = undefined, params = {}) {
- await this.loadMarkets ();
- const response = await this.publicPostReturnTicker (params);
- // { ETH_BOUNCY:
- // { last: '0.000000004000088005',
- // high: 'N/A',
- // low: 'N/A',
- // lowestAsk: '0.00000000599885995',
- // highestBid: '0.000000001400500103',
- // percentChange: '0',
- // baseVolume: '0',
- // quoteVolume: '0' },
- // ETH_NBAI:
- // { last: '0.0000032',
- // high: 'N/A',
- // low: 'N/A',
- // lowestAsk: '0.000004000199999502',
- // highestBid: '0.0000016002',
- // percentChange: '0',
- // baseVolume: '0',
- // quoteVolume: '0' }, }
- const ids = Object.keys (response);
- const result = {};
- for (let i = 0; i < ids.length; i++) {
- const id = ids[i];
- let symbol = undefined;
- let market = undefined;
- if (id in this.markets_by_id) {
- market = this.markets_by_id[id];
- symbol = market['symbol'];
- } else {
- const [ quoteId, baseId ] = id.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- market = { 'symbol': symbol };
- }
- const ticker = response[id];
- result[symbol] = this.parseTicker (ticker, market);
- }
- return this.filterByArray (result, 'symbol', symbols);
- }
-
async fetchTicker (symbol, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'market': market['id'],
};
- const response = await this.publicPostReturnTicker (this.extend (request, params));
- // { last: '0.0016550916',
- // high: 'N/A',
- // low: 'N/A',
- // lowestAsk: '0.0016743368',
- // highestBid: '0.001163726270773897',
- // percentChange: '0',
- // baseVolume: '0',
- // quoteVolume: '0' }
- return this.parseTicker (response, market);
+ // [
+ // {
+ // market: 'DIL-ETH',
+ // time: 1598367493008,
+ // open: '0.09695361',
+ // high: '0.10245881',
+ // low: '0.09572507',
+ // close: '0.09917079',
+ // closeQuantity: '0.71320950',
+ // baseVolume: '309.17380612',
+ // quoteVolume: '30.57633981',
+ // percentChange: '2.28',
+ // numTrades: 205,
+ // ask: '0.09910476',
+ // bid: '0.09688340',
+ // sequence: 3902
+ // }
+ // ]
+ const response = await this.publicGetTickers (this.extend (request, params));
+ const ticker = this.safeValue (response, 0);
+ return this.parseTicker (ticker, market);
}
- async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ async fetchTickers (symbols = undefined, params = {}) {
await this.loadMarkets ();
- const market = this.market (symbol);
- const id = market['quote'] + '_' + market['base'];
- const request = {
- 'market': id,
- 'count': 100, // the default will only return one trade
- };
- if (limit !== undefined) {
- request['count'] = limit;
- }
- const response = await this.publicPostReturnOrderBook (this.extend (request, params));
- //
- // {
- // "asks": [
- // {
- // "price": "0.001675282799999",
- // "amount": "206.163978911921061732",
- // "total": "0.345382967850497906",
- // "orderHash": "0xfdf12c124a6a7fa4a8e1866b324da888c8e1b3ad209f5050d3a23df3397a5cb7",
- // "params": {
- // "tokenBuy": "0x0000000000000000000000000000000000000000",
- // "buySymbol": "ETH",
- // "buyPrecision": 18,
- // "amountBuy": "345382967850497906",
- // "tokenSell": "0xb98d4c97425d9908e66e53a6fdf673acca0be986",
- // "sellSymbol": "ABT",
- // "sellPrecision": 18,
- // "amountSell": "206163978911921061732",
- // "expires": 10000,
- // "nonce": 13489307413,
- // "user": "0x9e8ef79316a4a79bbf55a5f9c16b3e068fff65c6"
- // }
- // }
- // ],
- // "bids": [
- // {
- // "price": "0.001161865193232242",
- // "amount": "854.393661648355",
- // "total": "0.992690256787469029",
- // "orderHash": "0x2f2baaf982085e4096f9e23e376214885fa74b2939497968e92222716fc2c86d",
- // "params": {
- // "tokenBuy": "0xb98d4c97425d9908e66e53a6fdf673acca0be986",
- // "buySymbol": "ABT",
- // "buyPrecision": 18,
- // "amountBuy": "854393661648355000000",
- // "tokenSell": "0x0000000000000000000000000000000000000000",
- // "sellSymbol": "ETH",
- // "sellPrecision": 18,
- // "amountSell": "992690256787469029",
- // "expires": 10000,
- // "nonce": 18155189676,
- // "user": "0xb631284dd7b74a846af5b37766ceb1f85d53eca4"
- // }
- // }
- // ]
- // }
- //
- return this.parseOrderBook (response, undefined, 'bids', 'asks', 'price', 'amount');
+ // [
+ // {
+ // market: 'DIL-ETH',
+ // time: 1598367493008,
+ // open: '0.09695361',
+ // high: '0.10245881',
+ // low: '0.09572507',
+ // close: '0.09917079',
+ // closeQuantity: '0.71320950',
+ // baseVolume: '309.17380612',
+ // quoteVolume: '30.57633981',
+ // percentChange: '2.28',
+ // numTrades: 205,
+ // ask: '0.09910476',
+ // bid: '0.09688340',
+ // sequence: 3902
+ // }, ...
+ // ]
+ const response = await this.publicGetTickers (params);
+ return this.parseTickers (response, symbols);
}
- parseBidAsk (bidAsk, priceKey = 0, amountKey = 1) {
- const price = this.safeFloat (bidAsk, priceKey);
- const amount = this.safeFloat (bidAsk, amountKey);
- const info = bidAsk;
- return [price, amount, info];
+ parseTickers (rawTickers, symbols = undefined) {
+ const tickers = [];
+ for (let i = 0; i < rawTickers.length; i++) {
+ tickers.push (this.parseTicker (rawTickers[i]));
+ }
+ return this.filterByArray (tickers, 'symbol', symbols);
}
- async fetchBalance (params = {}) {
- const request = {
- 'address': this.walletAddress,
- };
- const response = await this.publicPostReturnCompleteBalances (this.extend (request, params));
- //
- // {
- // ETH: { available: '0.0167', onOrders: '0.1533' }
- // }
- //
- const result = {
- 'info': response,
- };
- const keys = Object.keys (response);
- for (let i = 0; i < keys.length; i++) {
- const currency = keys[i];
- const balance = response[currency];
- const code = this.safeCurrencyCode (currency);
- result[code] = {
- 'free': this.safeFloat (balance, 'available'),
- 'used': this.safeFloat (balance, 'onOrders'),
- };
+ parseTicker (ticker, market = undefined) {
+ // {
+ // market: 'DIL-ETH',
+ // time: 1598367493008,
+ // open: '0.09695361',
+ // high: '0.10245881',
+ // low: '0.09572507',
+ // close: '0.09917079',
+ // closeQuantity: '0.71320950',
+ // baseVolume: '309.17380612',
+ // quoteVolume: '30.57633981',
+ // percentChange: '2.28',
+ // numTrades: 205,
+ // ask: '0.09910476',
+ // bid: '0.09688340',
+ // sequence: 3902
+ // }
+ const marketId = this.safeString (ticker, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const baseVolume = this.safeFloat (ticker, 'baseVolume');
+ const quoteVolume = this.safeFloat (ticker, 'quoteVolume');
+ const timestamp = this.safeInteger (ticker, 'time');
+ const open = this.safeFloat (ticker, 'open');
+ const high = this.safeFloat (ticker, 'high');
+ const low = this.safeFloat (ticker, 'low');
+ const close = this.safeFloat (ticker, 'close');
+ const ask = this.safeFloat (ticker, 'ask');
+ const bid = this.safeFloat (ticker, 'bid');
+ let percentage = this.safeFloat (ticker, 'percentChange');
+ if (percentage !== undefined) {
+ percentage = 1 + percentage / 100;
}
- return this.parseBalance (result);
- }
-
- async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- this.checkRequiredDependencies ();
- await this.loadMarkets ();
- const market = this.market (symbol);
- if (type === 'limit') {
- const expires = 100000;
- const contractAddress = await this.getContractAddress ();
- let tokenBuy = undefined;
- let tokenSell = undefined;
- let amountBuy = undefined;
- let amountSell = undefined;
- const quoteAmount = parseFloat (price) * parseFloat (amount);
- if (side === 'buy') {
- tokenBuy = market['baseId'];
- tokenSell = market['quoteId'];
- amountBuy = this.toWei (amount, market['precision']['amount']);
- amountSell = this.toWei (quoteAmount, 18);
- } else {
- tokenBuy = market['quoteId'];
- tokenSell = market['baseId'];
- amountBuy = this.toWei (quoteAmount, 18);
- amountSell = this.toWei (amount, market['precision']['amount']);
- }
- const nonce = await this.getNonce ();
- const orderToHash = {
- 'contractAddress': contractAddress,
- 'tokenBuy': tokenBuy,
- 'amountBuy': amountBuy,
- 'tokenSell': tokenSell,
- 'amountSell': amountSell,
- 'expires': expires,
- 'nonce': nonce,
- 'address': this.walletAddress,
- };
- const orderHash = this.getIdexCreateOrderHash (orderToHash);
- const signature = this.signMessage (orderHash, this.privateKey);
- const request = {
- 'tokenBuy': tokenBuy,
- 'amountBuy': amountBuy,
- 'tokenSell': tokenSell,
- 'amountSell': amountSell,
- 'address': this.walletAddress,
- 'nonce': nonce,
- 'expires': expires,
- };
- const response = await this.privatePostOrder (this.extend (request, signature)); // this.extend (request, params) will cause invalid signature
- // { orderNumber: 1562323021,
- // orderHash:
- // '0x31c42154a8421425a18d076df400d9ec1ef64d5251285384a71ba3c0ab31beb4',
- // timestamp: 1564041428,
- // price: '0.00073',
- // amount: '210',
- // total: '0.1533',
- // type: 'buy',
- // params:
- // { tokenBuy: '0x763fa6806e1acf68130d2d0f0df754c93cc546b2',
- // buyPrecision: 18,
- // amountBuy: '210000000000000000000',
- // tokenSell: '0x0000000000000000000000000000000000000000',
- // sellPrecision: 18,
- // amountSell: '153300000000000000',
- // expires: 100000,
- // nonce: 1,
- // user: '0x0ab991497116f7f5532a4c2f4f7b1784488628e1' } }
- return this.parseOrder (response, market);
- } else if (type === 'market') {
- if (!('orderHash' in params)) {
- throw new ArgumentsRequired (this.id + ' market order requires an order structure such as that in fetchOrderBook()[\'bids\'][0][2], fetchOrder()[\'info\'], or fetchOpenOrders()[0][\'info\']');
- }
- // { price: '0.000132247803328924',
- // amount: '19980',
- // total: '2.6423111105119',
- // orderHash:
- // '0x5fb3452b3d13fc013585b51c91c43a0fbe4298c211243763c49437848c274749',
- // params:
- // { tokenBuy: '0x0000000000000000000000000000000000000000',
- // buySymbol: 'ETH',
- // buyPrecision: 18,
- // amountBuy: '2642311110511900000',
- // tokenSell: '0xb705268213d593b8fd88d3fdeff93aff5cbdcfae',
- // sellSymbol: 'IDEX',
- // sellPrecision: 18,
- // amountSell: '19980000000000000000000',
- // expires: 10000,
- // nonce: 1564656561510,
- // user: '0xc3f8304270e49b8e8197bfcfd8567b83d9e4479b' } }
- const orderToSign = {
- 'orderHash': params['orderHash'],
- 'amount': params['params']['amountBuy'],
- 'address': params['params']['user'],
- 'nonce': params['params']['nonce'],
- };
- const orderHash = this.getIdexMarketOrderHash (orderToSign);
- const signature = this.signMessage (orderHash, this.privateKey);
- const signedOrder = this.extend (orderToSign, signature);
- signedOrder['address'] = this.walletAddress;
- signedOrder['nonce'] = await this.getNonce ();
- // [ {
- // "amount": "0.07",
- // "date": "2017-10-13 16:25:36",
- // "total": "0.49",
- // "market": "ETH_DVIP",
- // "type": "buy",
- // "price": "7",
- // "orderHash": "0xcfe4018c59e50e0e1964c979e6213ce5eb8c751cbc98a44251eb48a0985adc52",
- // "uuid": "250d51a0-b033-11e7-9984-a9ab79bb8f35"
- // } ]
- const response = await this.privatePostTrade (signedOrder);
- return this.parseOrders (response, market);
+ let change = undefined;
+ if ((close !== undefined) && (open !== undefined)) {
+ change = close - open;
}
- }
-
- async getNonce () {
- if (this.options['orderNonce'] === undefined) {
- const response = await this.publicPostReturnNextNonce ({
- 'address': this.walletAddress,
- });
- return this.safeInteger (response, 'nonce');
- } else {
- const result = this.options['orderNonce'];
- this.options['orderNonce'] = this.sum (this.options['orderNonce'], 1);
- return result;
- }
- }
-
- async getContractAddress () {
- if (this.options['contractAddress'] !== undefined) {
- return this.options['contractAddress'];
- }
- const response = await this.publicPostReturnContractAddress ();
- this.options['contractAddress'] = this.safeString (response, 'address');
- return this.options['contractAddress'];
- }
-
- async cancelOrder (orderId, symbol = undefined, params = {}) {
- const nonce = await this.getNonce ();
- const orderToHash = {
- 'orderHash': orderId,
- 'nonce': nonce,
- };
- const orderHash = this.getIdexCancelOrderHash (orderToHash);
- const signature = this.signMessage (orderHash, this.privateKey);
- const request = {
- 'orderHash': orderId,
- 'address': this.walletAddress,
- 'nonce': nonce,
- };
- const response = await this.privatePostCancel (this.extend (request, signature));
- // { success: 1 }
- if ('success' in response) {
- return {
- 'info': response,
- };
- } else {
- throw new ExchangeError (this.id + ' cancel order failed ' + this.json (response));
- }
- }
-
- async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const currency = this.currency (code);
- const request = {
- 'address': this.walletAddress,
- };
- if (since !== undefined) {
- request['start'] = parseInt (Math.floor (since / 1000));
- }
- const response = await this.publicPostReturnDepositsWithdrawals (this.extend (request, params));
- // { deposits:
- // [ { currency: 'ETH',
- // amount: '0.05',
- // timestamp: 1563953513,
- // transactionHash:
- // '0xd6eefd81c7efc9beeb35b924d6db3c93a78bf7eac082ba87e107ad4e94bccdcf',
- // depositNumber: 1586430 },
- // { currency: 'ETH',
- // amount: '0.12',
- // timestamp: 1564040359,
- // transactionHash:
- // '0x2ecbb3ab72b6f79fc7a9058c39dce28f913152748c1507d13ab1759e965da3ca',
- // depositNumber: 1587341 } ],
- // withdrawals:
- // [ { currency: 'ETH',
- // amount: '0.149',
- // timestamp: 1564060001,
- // transactionHash:
- // '0xab555fc301779dd92fd41ccd143b1d72776ae7b5acfc59ca44a1d376f68fda15',
- // withdrawalNumber: 1444070,
- // status: 'COMPLETE' } ] }
- const deposits = this.parseTransactions (response['deposits'], currency, since, limit);
- const withdrawals = this.parseTransactions (response['withdrawals'], currency, since, limit);
- return this.arrayConcat (deposits, withdrawals);
- }
-
- parseTransaction (item, currency = undefined) {
- // { currency: 'ETH',
- // amount: '0.05',
- // timestamp: 1563953513,
- // transactionHash:
- // '0xd6eefd81c7efc9beeb35b924d6db3c93a78bf7eac082ba87e107ad4e94bccdcf',
- // depositNumber: 1586430 }
- const amount = this.safeFloat (item, 'amount');
- const timestamp = this.safeTimestamp (item, 'timestamp');
- const txhash = this.safeString (item, 'transactionHash');
- let id = undefined;
- let type = undefined;
- let status = undefined;
- let addressFrom = undefined;
- let addressTo = undefined;
- if ('depositNumber' in item) {
- id = this.safeString (item, 'depositNumber');
- type = 'deposit';
- addressFrom = this.walletAddress;
- addressTo = this.options['contractAddress'];
- } else if ('withdrawalNumber' in item) {
- id = this.safeString (item, 'withdrawalNumber');
- type = 'withdrawal';
- status = this.parseTransactionStatus (this.safeString (item, 'status'));
- addressFrom = this.options['contractAddress'];
- addressTo = this.walletAddress;
- }
- const code = this.safeCurrencyCode (this.safeString (item, 'currency'));
return {
- 'info': item,
- 'id': id,
- 'txid': txhash,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'currency': code,
- 'amount': amount,
- 'status': status,
- 'type': type,
- 'updated': undefined,
- 'comment': undefined,
- 'addressFrom': addressFrom,
- 'tagFrom': undefined,
- 'addressTo': addressTo,
- 'tagTo': undefined,
- 'fee': {
- 'currency': code,
- 'cost': undefined,
- 'rate': undefined,
- },
- };
- }
-
- parseTransactionStatus (status) {
- const statuses = {
- 'COMPLETE': 'ok',
- };
- return this.safeString (statuses, status);
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- if (this.walletAddress === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a walletAddress');
- }
- await this.loadMarkets ();
- const request = {
- 'address': this.walletAddress,
- };
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['market'] = market['id'];
- }
- const response = await this.publicPostReturnOpenOrders (this.extend (request, params));
- // [ { timestamp: 1564041428,
- // orderHash:
- // '0x31c42154a8421425a18d076df400d9ec1ef64d5251285384a71ba3c0ab31beb4',
- // orderNumber: 1562323021,
- // market: 'ETH_LIT',
- // type: 'buy',
- // params:
- // { tokenBuy: '0x763fa6806e1acf68130d2d0f0df754c93cc546b2',
- // buySymbol: 'LIT',
- // buyPrecision: 18,
- // amountBuy: '210000000000000000000',
- // tokenSell: '0x0000000000000000000000000000000000000000',
- // sellSymbol: 'ETH',
- // sellPrecision: 18,
- // amountSell: '153300000000000000',
- // expires: 100000,
- // nonce: 1,
- // user: '0x0ab991497116f7f5532a4c2f4f7b1784488628e1' },
- // price: '0.00073',
- // amount: '210',
- // status: 'open',
- // total: '0.1533' } ]
- return this.parseOrders (response, market, since, limit);
- }
-
- async fetchOrder (id, symbol = undefined, params = {}) {
- await this.loadMarkets ();
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- }
- const request = {
- 'orderHash': id,
- };
- const response = await this.publicPostReturnOrderStatus (this.extend (request, params));
- // { filled: '0',
- // initialAmount: '210',
- // timestamp: 1564041428,
- // orderHash:
- // '0x31c42154a8421425a18d076df400d9ec1ef64d5251285384a71ba3c0ab31beb4',
- // orderNumber: 1562323021,
- // market: 'ETH_LIT',
- // type: 'buy',
- // params:
- // { tokenBuy: '0x763fa6806e1acf68130d2d0f0df754c93cc546b2',
- // buySymbol: 'LIT',
- // buyPrecision: 18,
- // amountBuy: '210000000000000000000',
- // tokenSell: '0x0000000000000000000000000000000000000000',
- // sellSymbol: 'ETH',
- // sellPrecision: 18,
- // amountSell: '153300000000000000',
- // expires: 100000,
- // nonce: 1,
- // user: '0x0ab991497116f7f5532a4c2f4f7b1784488628e1' },
- // price: '0.00073',
- // amount: '210',
- // status: 'open',
- // total: '0.1533' }
- return this.parseOrder (response, market);
- }
-
- parseOrder (order, market = undefined) {
- // { filled: '0',
- // initialAmount: '210',
- // timestamp: 1564041428,
- // orderHash:
- // '0x31c42154a8421425a18d076df400d9ec1ef64d5251285384a71ba3c0ab31beb4',
- // orderNumber: 1562323021,
- // market: 'ETH_LIT',
- // type: 'buy',
- // params:
- // { tokenBuy: '0x763fa6806e1acf68130d2d0f0df754c93cc546b2',
- // buySymbol: 'LIT',
- // buyPrecision: 18,
- // amountBuy: '210000000000000000000',
- // tokenSell: '0x0000000000000000000000000000000000000000',
- // sellSymbol: 'ETH',
- // sellPrecision: 18,
- // amountSell: '153300000000000000',
- // expires: 100000,
- // nonce: 1,
- // user: '0x0ab991497116f7f5532a4c2f4f7b1784488628e1' },
- // price: '0.00073',
- // amount: '210',
- // status: 'open',
- // total: '0.1533' }
- const timestamp = this.safeTimestamp (order, 'timestamp');
- const side = this.safeString (order, 'type');
- let symbol = undefined;
- let amount = undefined;
- let remaining = undefined;
- if ('initialAmount' in order) {
- amount = this.safeFloat (order, 'initialAmount');
- remaining = this.safeFloat (order, 'amount');
- } else {
- amount = this.safeFloat (order, 'amount');
- }
- const filled = this.safeFloat (order, 'filled');
- const price = this.safeFloat (order, 'price');
- let cost = this.safeFloat (order, 'total');
- if ((cost !== undefined) && (filled !== undefined) && !cost) {
- cost = filled * price;
- }
- if ('market' in order) {
- const marketId = order['market'];
- symbol = this.markets_by_id[marketId]['symbol'];
- } else if ((side !== undefined) && ('params' in order)) {
- const params = order['params'];
- const buy = this.safeCurrencyCode (this.safeString (params, 'tokenBuy'));
- const sell = this.safeCurrencyCode (this.safeString (params, 'tokenSell'));
- if (buy !== undefined && sell !== undefined) {
- symbol = (side === 'buy') ? (buy + '/' + sell) : (sell + '/' + buy);
- }
- }
- if (symbol === undefined && market !== undefined) {
- symbol = market['symbol'];
- }
- const id = this.safeString (order, 'orderHash');
- const status = this.parseOrderStatus (this.safeString (order, 'status'));
- return {
- 'info': order,
- 'id': id,
- 'clientOrderId': undefined,
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'side': side,
- 'amount': amount,
- 'price': price,
- 'type': 'limit',
- 'filled': filled,
- 'remaining': remaining,
- 'cost': cost,
- 'status': status,
- 'lastTradeTimestamp': undefined,
+ 'high': high,
+ 'low': low,
+ 'bid': bid,
+ 'bidVolume': undefined,
+ 'ask': ask,
+ 'askVolume': undefined,
+ 'vwap': undefined,
+ 'open': open,
+ 'close': close,
+ 'last': close,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
'average': undefined,
- 'trades': undefined,
- 'fee': undefined,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
};
}
- parseOrderStatus (status) {
- const statuses = {
- 'open': 'open',
- };
- return this.safeString (statuses, status, status);
- }
-
- async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- if (this.walletAddress === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a walletAddress');
- }
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
+ const market = this.market (symbol);
const request = {
- 'address': this.walletAddress,
+ 'market': market['id'],
+ 'interval': timeframe,
};
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['market'] = market['id'];
+ if (since !== undefined) {
+ request['start'] = since;
}
if (limit !== undefined) {
- request['start'] = parseInt (Math.floor (limit));
+ request['limit'] = limit;
}
- const response = await this.publicPostReturnTradeHistory (this.extend (request, params));
- // { ETH_IDEX:
- // [ { type: 'buy',
- // date: '2019-07-25 11:24:41',
- // amount: '347.833140025692348611',
- // total: '0.050998794333719943',
- // uuid: 'cbdff960-aece-11e9-b566-c5d69c3be671',
- // tid: 4320867,
- // timestamp: 1564053881,
- // price: '0.000146618560640751',
- // taker: '0x0ab991497116f7f5532a4c2f4f7b1784488628e1',
- // maker: '0x1a961bc2e0d619d101f5f92a6be752132d7606e6',
- // orderHash:
- // '0xbec6485613a15be619c04c1425e8e821ebae42b88fa95ac4dfe8ba2beb363ee4',
- // transactionHash:
- // '0xf094e07b329ac8046e8f34db358415863c41daa36765c05516f4cf4f5b403ad1',
- // tokenBuy: '0x0000000000000000000000000000000000000000',
- // buyerFee: '0.695666280051384697',
- // gasFee: '28.986780264563232993',
- // sellerFee: '0.00005099879433372',
- // tokenSell: '0xb705268213d593b8fd88d3fdeff93aff5cbdcfae',
- // usdValue: '11.336926687304238214' } ] }
- //
- // if a symbol is specified in the request:
- //
- // [ { type: 'buy',
- // date: '2019-07-25 11:24:41',
- // amount: '347.833140025692348611',
- // total: '0.050998794333719943',
- // uuid: 'cbdff960-aece-11e9-b566-c5d69c3be671',
- // tid: 4320867,
- // timestamp: 1564053881,
- // price: '0.000146618560640751',
- // taker: '0x0ab991497116f7f5532a4c2f4f7b1784488628e1',
- // maker: '0x1a961bc2e0d619d101f5f92a6be752132d7606e6',
- // orderHash:
- // '0xbec6485613a15be619c04c1425e8e821ebae42b88fa95ac4dfe8ba2beb363ee4',
- // transactionHash:
- // '0xf094e07b329ac8046e8f34db358415863c41daa36765c05516f4cf4f5b403ad1',
- // tokenBuy: '0x0000000000000000000000000000000000000000',
- // buyerFee: '0.695666280051384697',
- // gasFee: '28.986780264563232993',
- // sellerFee: '0.00005099879433372',
- // tokenSell: '0xb705268213d593b8fd88d3fdeff93aff5cbdcfae',
- // usdValue: '11.336926687304238214' } ]
+ const response = await this.publicGetCandles (this.extend (request, params));
if (Array.isArray (response)) {
- return this.parseTrades (response, market, since, limit);
+ // [
+ // {
+ // start: 1598345580000,
+ // open: '0.09771286',
+ // high: '0.09771286',
+ // low: '0.09771286',
+ // close: '0.09771286',
+ // volume: '1.45340410',
+ // sequence: 3853
+ // }, ...
+ // ]
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
} else {
- let result = [];
- const marketIds = Object.keys (response);
- for (let i = 0; i < marketIds.length; i++) {
- const marketId = marketIds[i];
- const trades = response[marketId];
- const parsed = this.parseTrades (trades, market, since, limit);
- result = this.arrayConcat (result, parsed);
- }
- return result;
+ // {"nextTime":1595536440000}
+ return [];
}
}
+ parseOHLCV (ohlcv, market = undefined) {
+ // {
+ // start: 1598345580000,
+ // open: '0.09771286',
+ // high: '0.09771286',
+ // low: '0.09771286',
+ // close: '0.09771286',
+ // volume: '1.45340410',
+ // sequence: 3853
+ // }
+ const timestamp = this.safeInteger (ohlcv, 'start');
+ const open = this.safeFloat (ohlcv, 'open');
+ const high = this.safeFloat (ohlcv, 'high');
+ const low = this.safeFloat (ohlcv, 'low');
+ const close = this.safeFloat (ohlcv, 'close');
+ const volume = this.safeFloat (ohlcv, 'volume');
+ return [ timestamp, open, high, low, close, volume ];
+ }
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'market': market['id'],
};
- if (limit !== undefined) {
- request['start'] = parseInt (Math.floor (limit));
+ if (since !== undefined) {
+ request['start'] = since;
}
- const response = await this.publicPostReturnTradeHistory (this.extend (request, params));
- // [ { type: 'buy',
- // date: '2019-07-25 11:24:41',
- // amount: '347.833140025692348611',
- // total: '0.050998794333719943',
- // uuid: 'cbdff960-aece-11e9-b566-c5d69c3be671',
- // tid: 4320867,
- // timestamp: 1564053881,
- // price: '0.000146618560640751',
- // taker: '0x0ab991497116f7f5532a4c2f4f7b1784488628e1',
- // maker: '0x1a961bc2e0d619d101f5f92a6be752132d7606e6',
- // orderHash:
- // '0xbec6485613a15be619c04c1425e8e821ebae42b88fa95ac4dfe8ba2beb363ee4',
- // transactionHash:
- // '0xf094e07b329ac8046e8f34db358415863c41daa36765c05516f4cf4f5b403ad1',
- // tokenBuy: '0x0000000000000000000000000000000000000000',
- // buyerFee: '0.695666280051384697',
- // gasFee: '28.986780264563232993',
- // sellerFee: '0.00005099879433372',
- // tokenSell: '0xb705268213d593b8fd88d3fdeff93aff5cbdcfae',
- // usdValue: '11.336926687304238214' } ]
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ // [
+ // {
+ // fillId: 'b5467d00-b13e-3fa9-8216-dd66735550fc',
+ // price: '0.09771286',
+ // quantity: '1.45340410',
+ // quoteQuantity: '0.14201627',
+ // time: 1598345638994,
+ // makerSide: 'buy',
+ // sequence: 3853
+ // }, ...
+ // ]
+ const response = await this.publicGetTrades (this.extend (request, params));
return this.parseTrades (response, market, since, limit);
}
parseTrade (trade, market = undefined) {
- // { type: 'buy',
- // date: '2019-07-25 11:24:41',
- // amount: '347.833140025692348611',
- // total: '0.050998794333719943',
- // uuid: 'cbdff960-aece-11e9-b566-c5d69c3be671',
- // tid: 4320867,
- // timestamp: 1564053881,
- // price: '0.000146618560640751',
- // taker: '0x0ab991497116f7f5532a4c2f4f7b1784488628e1',
- // maker: '0x1a961bc2e0d619d101f5f92a6be752132d7606e6',
- // orderHash:
- // '0xbec6485613a15be619c04c1425e8e821ebae42b88fa95ac4dfe8ba2beb363ee4',
- // transactionHash:
- // '0xf094e07b329ac8046e8f34db358415863c41daa36765c05516f4cf4f5b403ad1',
- // tokenBuy: '0x0000000000000000000000000000000000000000',
- // buyerFee: '0.695666280051384697',
- // gasFee: '28.986780264563232993',
- // sellerFee: '0.00005099879433372',
- // tokenSell: '0xb705268213d593b8fd88d3fdeff93aff5cbdcfae',
- // usdValue: '11.336926687304238214' }
- const side = this.safeString (trade, 'type');
- let feeCurrency = undefined;
- let symbol = undefined;
- const maker = this.safeString (trade, 'maker');
- let takerOrMaker = undefined;
- if (maker !== undefined && this.walletAddress !== undefined) {
- if (maker.toLowerCase () === this.walletAddress.toLowerCase ()) {
- takerOrMaker = 'maker';
- } else {
- takerOrMaker = 'taker';
- }
- }
- const buy = this.safeCurrencyCode (this.safeString (trade, 'tokenBuy'));
- const sell = this.safeCurrencyCode (this.safeString (trade, 'tokenSell'));
- // get ready to be mind-boggled
- let feeSide = undefined;
- if (buy !== undefined && sell !== undefined) {
- if (side === 'buy') {
- feeSide = 'buyerFee';
- if (takerOrMaker === 'maker') {
- symbol = buy + '/' + sell;
- feeCurrency = buy;
- } else {
- symbol = sell + '/' + buy;
- feeCurrency = sell;
- }
- } else {
- feeSide = 'sellerFee';
- if (takerOrMaker === 'maker') {
- symbol = sell + '/' + buy;
- feeCurrency = buy;
- } else {
- symbol = buy + '/' + sell;
- feeCurrency = sell;
- }
- }
- }
- if (symbol === undefined && market !== undefined) {
- symbol = market['symbol'];
- }
- const timestamp = this.safeTimestamp (trade, 'timestamp');
- const id = this.safeString (trade, 'tid');
- const amount = this.safeFloat (trade, 'amount');
+ // public trades
+ // {
+ // fillId: 'b5467d00-b13e-3fa9-8216-dd66735550fc',
+ // price: '0.09771286',
+ // quantity: '1.45340410',
+ // quoteQuantity: '0.14201627',
+ // time: 1598345638994,
+ // makerSide: 'buy',
+ // sequence: 3853
+ // }
+ // private trades
+ // {
+ // fillId: '48582d10-b9bb-3c4b-94d3-e67537cf2472',
+ // price: '0.09905990',
+ // quantity: '0.40000000',
+ // quoteQuantity: '0.03962396',
+ // time: 1598873478762,
+ // makerSide: 'sell',
+ // sequence: 5053,
+ // market: 'DIL-ETH',
+ // orderId: '7cdc8e90-eb7d-11ea-9e60-4118569f6e63',
+ // side: 'buy',
+ // fee: '0.00080000',
+ // feeAsset: 'DIL',
+ // gas: '0.00857497',
+ // liquidity: 'taker',
+ // txId: '0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65',
+ // txStatus: 'mined'
+ // }
+ const id = this.safeString (trade, 'fillId');
const price = this.safeFloat (trade, 'price');
- const cost = this.safeFloat (trade, 'total');
- let feeCost = this.safeFloat (trade, feeSide);
- if (feeCost < 0) {
- const gasFee = this.safeFloat (trade, 'gasFee');
- feeCost = this.sum (gasFee, feeCost);
+ const amount = this.safeFloat (trade, 'quantity');
+ const cost = this.safeFloat (trade, 'quoteQuantity');
+ const timestamp = this.safeInteger (trade, 'time');
+ const marketId = this.safeString (trade, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ // this code handles the duality of public vs private trades
+ const makerSide = this.safeString (trade, 'makerSide');
+ const oppositeSide = (makerSide === 'buy') ? 'sell' : 'buy';
+ const side = this.safeString (trade, 'side', oppositeSide);
+ const takerOrMaker = this.safeString (trade, 'liquidity', 'taker');
+ const feeCost = this.safeFloat (trade, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (trade, 'feeAsset');
+ fee = {
+ 'cost': feeCost,
+ 'currency': this.safeCurrencyCode (feeCurrencyId),
+ };
}
- const fee = {
- 'currency': feeCurrency,
- 'cost': feeCost,
- };
- if (feeCost !== undefined && amount !== undefined) {
- const feeCurrencyAmount = (feeCurrency === 'ETH') ? cost : amount;
- fee['rate'] = feeCost / feeCurrencyAmount;
- }
- const orderId = this.safeString (trade, 'orderHash');
+ const orderId = this.safeString (trade, 'orderId');
return {
'info': trade,
- 'id': id,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'fee': fee,
+ 'symbol': symbol,
+ 'id': id,
+ 'order': orderId,
+ 'type': 'limit',
+ 'side': side,
+ 'takerOrMaker': takerOrMaker,
'price': price,
'amount': amount,
'cost': cost,
- 'takerOrMaker': takerOrMaker,
- 'side': side,
- 'order': orderId,
- 'symbol': symbol,
- 'type': 'limit',
+ 'fee': fee,
};
}
- async withdraw (code, amount, address, tag = undefined, params = {}) {
- this.checkRequiredDependencies ();
- this.checkAddress (address);
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
- const currency = this.currency (code);
- const tokenAddress = currency['id'];
- const nonce = await this.getNonce ();
- amount = this.toWei (amount, currency['precision']);
- const requestToHash = {
- 'contractAddress': await this.getContractAddress (),
- 'token': tokenAddress,
- 'amount': amount,
- 'address': address,
- 'nonce': nonce,
- };
- const hash = this.getIdexWithdrawHash (requestToHash);
- const signature = this.signMessage (hash, this.privateKey);
+ const market = this.market (symbol);
const request = {
- 'address': address,
- 'amount': amount,
- 'token': tokenAddress,
- 'nonce': nonce,
+ 'market': market['id'],
+ 'level': 2,
};
- const response = await this.privatePostWithdraw (this.extend (request, signature));
- // { amount: '0' }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ // {
+ // sequence: 36416753,
+ // bids: [
+ // [ '0.09672815', '8.22284267', 1 ],
+ // [ '0.09672814', '1.83685554', 1 ],
+ // [ '0.09672143', '4.10962617', 1 ],
+ // [ '0.09658884', '4.03863759', 1 ],
+ // [ '0.09653781', '3.35730684', 1 ],
+ // [ '0.09624660', '2.54163586', 1 ],
+ // [ '0.09617490', '1.93065030', 1 ]
+ // ],
+ // asks: [
+ // [ '0.09910476', '3.22840154', 1 ],
+ // [ '0.09940587', '3.39796593', 1 ],
+ // [ '0.09948189', '4.25088898', 1 ],
+ // [ '0.09958362', '2.42195784', 1 ],
+ // [ '0.09974393', '4.25234367', 1 ],
+ // [ '0.09995250', '3.40192141', 1 ]
+ // ]
+ // }
+ const response = await this.publicGetOrderbook (this.extend (request, params));
+ const nonce = this.safeInteger (response, 'sequence');
+ return {
+ 'timestamp': undefined,
+ 'datetime': undefined,
+ 'nonce': nonce,
+ 'bids': this.parseSide (response, 'bids'),
+ 'asks': this.parseSide (response, 'asks'),
+ };
+ }
+
+ parseSide (book, side) {
+ const bookSide = this.safeValue (book, side, []);
+ const result = [];
+ for (let i = 0; i < bookSide.length; i++) {
+ const order = bookSide[i];
+ const price = this.safeFloat (order, 0);
+ const amount = this.safeFloat (order, 1);
+ const orderCount = this.safeInteger (order, 2);
+ result.push ([ price, amount, orderCount ]);
+ }
+ const descending = side === 'bids';
+ return this.sortBy (result, 0, descending);
+ }
+
+ async fetchCurrencies (params = {}) {
+ // [
+ // {
+ // name: 'Ether',
+ // symbol: 'ETH',
+ // contractAddress: '0x0000000000000000000000000000000000000000',
+ // assetDecimals: 18,
+ // exchangeDecimals: 8
+ // }, ..
+ // ]
+ const response = await this.publicGetAssets (params);
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const entry = response[i];
+ const name = this.safeString (entry, 'name');
+ const currencyId = this.safeString (entry, 'symbol');
+ const precision = this.safeInteger (entry, 'exchangeDecimals');
+ const code = this.safeCurrencyCode (currencyId);
+ const lot = Math.pow (-10, precision);
+ result[code] = {
+ 'id': currencyId,
+ 'code': code,
+ 'info': entry,
+ 'type': undefined,
+ 'name': name,
+ 'active': undefined,
+ 'fee': undefined,
+ 'precision': precision,
+ 'limits': {
+ 'amount': { 'min': lot, 'max': undefined },
+ 'price': { 'min': lot, 'max': undefined },
+ 'cost': { 'min': undefined, 'max': undefined },
+ 'withdraw': { 'min': lot, 'max': undefined },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchBalance (params = {}) {
+ this.checkRequiredCredentials ();
+ await this.loadMarkets ();
+ const nonce1 = this.uuidv1 ();
+ const request = {
+ 'nonce': nonce1,
+ 'wallet': this.walletAddress,
+ };
+ // [
+ // {
+ // asset: 'DIL',
+ // quantity: '0.00000000',
+ // availableForTrade: '0.00000000',
+ // locked: '0.00000000',
+ // usdValue: null
+ // }, ...
+ // ]
+ const extendedRequest = this.extend (request, params);
+ if (extendedRequest['wallet'] === undefined) {
+ throw new BadRequest (this.id + ' wallet is undefined, set this.walletAddress or "address" in params');
+ }
+ let response = undefined;
+ try {
+ response = await this.privateGetBalances (extendedRequest);
+ } catch (e) {
+ if (e instanceof InvalidAddress) {
+ const walletAddress = extendedRequest['wallet'];
+ await this.associateWallet (walletAddress);
+ response = await this.privateGetBalances (extendedRequest);
+ } else {
+ throw e;
+ }
+ }
+ const result = {
+ 'info': response,
+ };
+ for (let i = 0; i < response.length; i++) {
+ const entry = response[i];
+ const currencyId = this.safeString (entry, 'asset');
+ const code = this.safeCurrencyCode (currencyId);
+ const total = this.safeFloat (entry, 'quantity');
+ const free = this.safeFloat (entry, 'availableForTrade');
+ const used = this.safeFloat (entry, 'locked');
+ result[code] = {
+ 'free': free,
+ 'used': used,
+ 'total': total,
+ };
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ this.checkRequiredCredentials ();
+ await this.loadMarkets ();
+ let market = undefined;
+ const request = {
+ 'nonce': this.uuidv1 (),
+ 'wallet': this.walletAddress,
+ };
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ // [
+ // {
+ // fillId: '48582d10-b9bb-3c4b-94d3-e67537cf2472',
+ // price: '0.09905990',
+ // quantity: '0.40000000',
+ // quoteQuantity: '0.03962396',
+ // time: 1598873478762,
+ // makerSide: 'sell',
+ // sequence: 5053,
+ // market: 'DIL-ETH',
+ // orderId: '7cdc8e90-eb7d-11ea-9e60-4118569f6e63',
+ // side: 'buy',
+ // fee: '0.00080000',
+ // feeAsset: 'DIL',
+ // gas: '0.00857497',
+ // liquidity: 'taker',
+ // txId: '0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65',
+ // txStatus: 'mined'
+ // }
+ // ]
+ const extendedRequest = this.extend (request, params);
+ if (extendedRequest['wallet'] === undefined) {
+ throw new BadRequest (this.id + ' walletAddress is undefined, set this.walletAddress or "address" in params');
+ }
+ let response = undefined;
+ try {
+ response = await this.privateGetFills (extendedRequest);
+ } catch (e) {
+ if (e instanceof InvalidAddress) {
+ const walletAddress = extendedRequest['wallet'];
+ await this.associateWallet (walletAddress);
+ response = await this.privateGetFills (extendedRequest);
+ } else {
+ throw e;
+ }
+ }
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ const request = {
+ 'orderId': id,
+ };
+ return await this.fetchOrdersHelper (symbol, undefined, undefined, this.extend (request, params));
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'closed': false,
+ };
+ return await this.fetchOrdersHelper (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'closed': true,
+ };
+ return await this.fetchOrdersHelper (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchOrdersHelper (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'nonce': this.uuidv1 (),
+ 'wallet': this.walletAddress,
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetOrders (this.extend (request, params));
+ // fetchClosedOrders / fetchOpenOrders
+ // [
+ // {
+ // "market": "DIL-ETH",
+ // "orderId": "7cdc8e90-eb7d-11ea-9e60-4118569f6e63",
+ // "wallet": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
+ // "time": 1598873478650,
+ // "status": "filled",
+ // "type": "limit",
+ // "side": "buy",
+ // "originalQuantity": "0.40000000",
+ // "executedQuantity": "0.40000000",
+ // "cumulativeQuoteQuantity": "0.03962396",
+ // "avgExecutionPrice": "0.09905990",
+ // "price": "1.00000000",
+ // "fills": [
+ // {
+ // "fillId": "48582d10-b9bb-3c4b-94d3-e67537cf2472",
+ // "price": "0.09905990",
+ // "quantity": "0.40000000",
+ // "quoteQuantity": "0.03962396",
+ // "time": 1598873478650,
+ // "makerSide": "sell",
+ // "sequence": 5053,
+ // "fee": "0.00080000",
+ // "feeAsset": "DIL",
+ // "gas": "0.00857497",
+ // "liquidity": "taker",
+ // "txId": "0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65",
+ // "txStatus": "mined"
+ // }
+ // ]
+ // }
+ // ]
+ // fetchOrder
+ // { market: 'DIL-ETH',
+ // orderId: '7cdc8e90-eb7d-11ea-9e60-4118569f6e63',
+ // wallet: '0x0AB991497116f7F5532a4c2f4f7B1784488628e1',
+ // time: 1598873478650,
+ // status: 'filled',
+ // type: 'limit',
+ // side: 'buy',
+ // originalQuantity: '0.40000000',
+ // executedQuantity: '0.40000000',
+ // cumulativeQuoteQuantity: '0.03962396',
+ // avgExecutionPrice: '0.09905990',
+ // price: '1.00000000',
+ // fills:
+ // [ { fillId: '48582d10-b9bb-3c4b-94d3-e67537cf2472',
+ // price: '0.09905990',
+ // quantity: '0.40000000',
+ // quoteQuantity: '0.03962396',
+ // time: 1598873478650,
+ // makerSide: 'sell',
+ // sequence: 5053,
+ // fee: '0.00080000',
+ // feeAsset: 'DIL',
+ // gas: '0.00857497',
+ // liquidity: 'taker',
+ // txId: '0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65',
+ // txStatus: 'mined' } ] }
+ if (Array.isArray (response)) {
+ return this.parseOrders (response, market, since, limit);
+ } else {
+ return this.parseOrder (response, market);
+ }
+ }
+
+ parseOrderStatus (status) {
+ // https://docs.idex.io/#order-states-amp-lifecycle
+ const statuses = {
+ 'active': 'open',
+ 'partiallyFilled': 'open',
+ 'rejected': 'canceled',
+ 'filled': 'closed',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // {
+ // "market": "DIL-ETH",
+ // "orderId": "7cdc8e90-eb7d-11ea-9e60-4118569f6e63",
+ // "wallet": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
+ // "time": 1598873478650,
+ // "status": "filled",
+ // "type": "limit",
+ // "side": "buy",
+ // "originalQuantity": "0.40000000",
+ // "executedQuantity": "0.40000000",
+ // "cumulativeQuoteQuantity": "0.03962396",
+ // "avgExecutionPrice": "0.09905990",
+ // "price": "1.00000000",
+ // "fills": [
+ // {
+ // "fillId": "48582d10-b9bb-3c4b-94d3-e67537cf2472",
+ // "price": "0.09905990",
+ // "quantity": "0.40000000",
+ // "quoteQuantity": "0.03962396",
+ // "time": 1598873478650,
+ // "makerSide": "sell",
+ // "sequence": 5053,
+ // "fee": "0.00080000",
+ // "feeAsset": "DIL",
+ // "gas": "0.00857497",
+ // "liquidity": "taker",
+ // "txId": "0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65",
+ // "txStatus": "mined"
+ // }
+ // ]
+ // }
+ //
+ const timestamp = this.safeInteger (order, 'time');
+ const fills = this.safeValue (order, 'fills', []);
+ const id = this.safeString (order, 'orderId');
+ const clientOrderId = this.safeString (order, 'clientOrderId');
+ const marketId = this.safeString (order, 'market');
+ const side = this.safeString (order, 'side');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const trades = this.parseTrades (fills, market);
+ const type = this.safeString (order, 'type');
+ const amount = this.safeFloat (order, 'originalQuantity');
+ const filled = this.safeFloat (order, 'executedQuantity');
+ let remaining = undefined;
+ if ((amount !== undefined) && (filled !== undefined)) {
+ remaining = amount - filled;
+ }
+ const average = this.safeFloat (order, 'avgExecutionPrice');
+ const price = this.safeFloat (order, 'price', average); // for market orders
+ let cost = undefined;
+ if ((amount !== undefined) && (price !== undefined)) {
+ cost = amount * price;
+ }
+ const rawStatus = this.safeString (order, 'status');
+ const status = this.parseOrderStatus (rawStatus);
+ const fee = {
+ 'currency': undefined,
+ 'cost': undefined,
+ };
+ let lastTrade = undefined;
+ for (let i = 0; i < trades.length; i++) {
+ lastTrade = trades[i];
+ fee['currency'] = lastTrade['fee']['currency'];
+ fee['cost'] = this.sum (fee['cost'], lastTrade['fee']['cost']);
+ }
+ const lastTradeTimestamp = this.safeInteger (lastTrade, 'timestamp');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': trades,
+ };
+ }
+
+ async associateWallet (walletAddress, params = {}) {
+ const nonce = this.uuidv1 ();
+ const noPrefix = this.remove0xPrefix (walletAddress);
+ const byteArray = [
+ this.base16ToBinary (nonce),
+ this.base16ToBinary (noPrefix),
+ ];
+ const binary = this.binaryConcatArray (byteArray);
+ const hash = this.hash (binary, 'keccak', 'hex');
+ const signature = this.signMessageString (hash, this.privateKey);
+ // {
+ // address: '0x0AB991497116f7F5532a4c2f4f7B1784488628e1',
+ // totalPortfolioValueUsd: '0.00',
+ // time: 1598468353626
+ // }
+ const request = {
+ 'parameters': {
+ 'nonce': nonce,
+ 'wallet': walletAddress,
+ },
+ 'signature': signature,
+ };
+ const result = await this.privatePostWallets (request);
+ return result;
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ // https://docs.idex.io/#create-order
+ this.checkRequiredCredentials ();
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const nonce = this.uuidv1 ();
+ let typeEnum = undefined;
+ const stopLossTypeEnums = {
+ 'stopLoss': 3,
+ 'stopLossLimit': 4,
+ 'takeProfit': 5,
+ 'takeProfitLimit': 6,
+ };
+ let stopPriceString = undefined;
+ if ((type === 'stopLossLimit') || (type === 'takeProfitLimit') || ('stopPrice' in params)) {
+ if (!('stopPrice' in params)) {
+ throw new BadRequest (this.id + ' stopPrice is a required parameter for ' + type + 'orders');
+ }
+ stopPriceString = this.priceToPrecision (symbol, params['stopPrice']);
+ }
+ const limitTypeEnums = {
+ 'limit': 1,
+ 'limitMaker': 2,
+ };
+ let priceString = undefined;
+ const typeLower = type.toLowerCase ();
+ const limitOrder = typeLower.indexOf ('limit') > -1;
+ if (type in limitTypeEnums) {
+ typeEnum = limitTypeEnums[type];
+ priceString = this.priceToPrecision (symbol, price);
+ } else if (type in stopLossTypeEnums) {
+ typeEnum = stopLossTypeEnums[type];
+ priceString = this.priceToPrecision (symbol, price);
+ } else if (type === 'market') {
+ typeEnum = 0;
+ } else {
+ throw new BadRequest (this.id + ' ' + type + ' is not a valid order type');
+ }
+ let amountEnum = 0; // base quantity
+ if ('quoteOrderQuantity' in params) {
+ if (type !== 'market') {
+ throw new NotSupported (this.id + ' quoteOrderQuantity is not supported for ' + type + ' orders, only supported for market orders');
+ }
+ amountEnum = 1;
+ amount = this.safeFloat (params, 'quoteOrderQuantity');
+ }
+ const sideEnum = (side === 'buy') ? 0 : 1;
+ const walletBytes = this.remove0xPrefix (this.walletAddress);
+ const orderVersion = 1;
+ const amountString = this.amountToPrecision (symbol, amount);
+ // https://docs.idex.io/#time-in-force
+ const timeInForceEnums = {
+ 'gtc': 0,
+ 'ioc': 2,
+ 'fok': 3,
+ };
+ const defaultTimeInForce = this.safeString (this.options, 'defaultTimeInForce', 'gtc');
+ const timeInForce = this.safeString (params, 'timeInForce', defaultTimeInForce);
+ let timeInForceEnum = undefined;
+ if (timeInForce in timeInForceEnums) {
+ timeInForceEnum = timeInForceEnums[timeInForce];
+ } else {
+ const allOptions = Object.keys (timeInForceEnums);
+ const asString = allOptions.join (', ');
+ throw new BadRequest (this.id + ' ' + timeInForce + ' is not a valid timeInForce, please choose one of ' + asString);
+ }
+ // https://docs.idex.io/#self-trade-prevention
+ const selfTradePreventionEnums = {
+ 'dc': 0,
+ 'co': 1,
+ 'cn': 2,
+ 'cb': 3,
+ };
+ const defaultSelfTradePrevention = this.safeString (this.options, 'defaultSelfTradePrevention', 'cn');
+ const selfTradePrevention = this.safeString (params, 'selfTradePrevention', defaultSelfTradePrevention);
+ let selfTradePreventionEnum = undefined;
+ if (selfTradePrevention in selfTradePreventionEnums) {
+ selfTradePreventionEnum = selfTradePreventionEnums[selfTradePrevention];
+ } else {
+ const allOptions = Object.keys (selfTradePreventionEnums);
+ const asString = allOptions.join (', ');
+ throw new BadRequest (this.id + ' ' + selfTradePrevention + ' is not a valid selfTradePrevention, please choose one of ' + asString);
+ }
+ const byteArray = [
+ this.numberToBE (orderVersion, 1),
+ this.base16ToBinary (nonce),
+ this.base16ToBinary (walletBytes),
+ this.stringToBinary (this.encode (market['id'])), // TODO: refactor to remove either encode or stringToBinary
+ this.numberToBE (typeEnum, 1),
+ this.numberToBE (sideEnum, 1),
+ this.stringToBinary (this.encode (amountString)),
+ this.numberToBE (amountEnum, 1),
+ ];
+ if (limitOrder) {
+ const encodedPrice = this.stringToBinary (this.encode (priceString));
+ byteArray.push (encodedPrice);
+ }
+ if (type in stopLossTypeEnums) {
+ const encodedPrice = this.stringToBinary (this.encode (stopPriceString || priceString));
+ byteArray.push (encodedPrice);
+ }
+ const clientOrderId = this.safeString (params, 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ byteArray.push (this.stringToBinary (this.encode (clientOrderId)));
+ }
+ const after = [
+ this.numberToBE (timeInForceEnum, 1),
+ this.numberToBE (selfTradePreventionEnum, 1),
+ this.numberToBE (0, 8), // unused
+ ];
+ const allBytes = this.arrayConcat (byteArray, after);
+ const binary = this.binaryConcatArray (allBytes);
+ const hash = this.hash (binary, 'keccak', 'hex');
+ const signature = this.signMessageString (hash, this.privateKey);
+ const request = {
+ 'parameters': {
+ 'nonce': nonce,
+ 'market': market['id'],
+ 'side': side,
+ 'type': type,
+ 'wallet': this.walletAddress,
+ 'timeInForce': timeInForce,
+ 'selfTradePrevention': selfTradePrevention,
+ },
+ 'signature': signature,
+ };
+ if (limitOrder) {
+ request['parameters']['price'] = priceString;
+ }
+ if (type in stopLossTypeEnums) {
+ request['parameters']['stopPrice'] = stopPriceString || priceString;
+ }
+ if (amountEnum === 0) {
+ request['parameters']['quantity'] = amountString;
+ } else {
+ request['parameters']['quoteOrderQuantity'] = amountString;
+ }
+ if (clientOrderId !== undefined) {
+ request['parameters']['clientOrderId'] = clientOrderId;
+ }
+ // {
+ // market: 'DIL-ETH',
+ // orderId: '7cdc8e90-eb7d-11ea-9e60-4118569f6e63',
+ // wallet: '0x0AB991497116f7F5532a4c2f4f7B1784488628e1',
+ // time: 1598873478650,
+ // status: 'filled',
+ // type: 'limit',
+ // side: 'buy',
+ // originalQuantity: '0.40000000',
+ // executedQuantity: '0.40000000',
+ // cumulativeQuoteQuantity: '0.03962396',
+ // price: '1.00000000',
+ // fills: [
+ // {
+ // fillId: '48582d10-b9bb-3c4b-94d3-e67537cf2472',
+ // price: '0.09905990',
+ // quantity: '0.40000000',
+ // quoteQuantity: '0.03962396',
+ // time: 1598873478650,
+ // makerSide: 'sell',
+ // sequence: 5053,
+ // fee: '0.00080000',
+ // feeAsset: 'DIL',
+ // gas: '0.00857497',
+ // liquidity: 'taker',
+ // txStatus: 'pending'
+ // }
+ // ],
+ // avgExecutionPrice: '0.09905990'
+ // }
+ // we don't use extend here because it is a signed endpoint
+ const response = await this.privatePostOrders (request);
+ return this.parseOrder (response, market);
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkRequiredCredentials ();
+ await this.loadMarkets ();
+ const nonce = this.uuidv1 ();
+ const amountString = this.currencyToPrecision (code, amount);
+ const currency = this.currency (code);
+ const walletBytes = this.remove0xPrefix (this.walletAddress);
+ const byteArray = [
+ this.base16ToBinary (nonce),
+ this.base16ToBinary (walletBytes),
+ this.stringToBinary (this.encode (currency['id'])),
+ this.stringToBinary (this.encode (amountString)),
+ this.numberToBE (1, 1), // bool set to true
+ ];
+ const binary = this.binaryConcatArray (byteArray);
+ const hash = this.hash (binary, 'keccak', 'hex');
+ const signature = this.signMessageString (hash, this.privateKey);
+ const request = {
+ 'parameters': {
+ 'nonce': nonce,
+ 'wallet': address,
+ 'asset': currency['id'],
+ 'quantity': amountString,
+ },
+ 'signature': signature,
+ };
+ // {
+ // withdrawalId: 'a61dcff0-ec4d-11ea-8b83-c78a6ecb3180',
+ // asset: 'ETH',
+ // assetContractAddress: '0x0000000000000000000000000000000000000000',
+ // quantity: '0.20000000',
+ // time: 1598962883190,
+ // fee: '0.00024000',
+ // txStatus: 'pending',
+ // txId: null
+ // }
+ const response = await this.privatePostWithdrawals (request);
+ const id = this.safeString (response, 'withdrawalId');
return {
'info': response,
- 'id': undefined,
+ 'id': id,
+ };
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ this.checkRequiredCredentials ();
+ await this.loadMarkets ();
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ const nonce = this.uuidv1 ();
+ const walletBytes = this.remove0xPrefix (this.walletAddress);
+ const byteArray = [
+ this.base16ToBinary (nonce),
+ this.base16ToBinary (walletBytes),
+ this.stringToBinary (this.encode (id)),
+ ];
+ const binary = this.binaryConcatArray (byteArray);
+ const hash = this.hash (binary, 'keccak', 'hex');
+ const signature = this.signMessageString (hash, this.privateKey);
+ const request = {
+ 'parameters': {
+ 'nonce': nonce,
+ 'wallet': this.walletAddress,
+ 'orderId': id,
+ },
+ 'signature': signature,
+ };
+ // [ { orderId: '688336f0-ec50-11ea-9842-b332f8a34d0e' } ]
+ const response = await this.privateDeleteOrders (this.extend (request, params));
+ const canceledOrder = this.safeValue (response, 0);
+ return this.parseOrder (canceledOrder, market);
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ const errorCode = this.safeString (response, 'code');
+ const message = this.safeString (response, 'message');
+ if (errorCode in this.exceptions) {
+ const Exception = this.exceptions[errorCode];
+ throw new Exception (this.id + ' ' + message);
+ }
+ if (errorCode !== undefined) {
+ throw new ExchangeError (this.id + ' ' + message);
+ }
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ params = this.extend ({
+ 'method': 'privateGetDeposits',
+ }, params);
+ return this.fetchTransactionsHelper (code, since, limit, params);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ params = this.extend ({
+ 'method': 'privateGetWithdrawals',
+ }, params);
+ return this.fetchTransactionsHelper (code, since, limit, params);
+ }
+
+ async fetchTransactionsHelper (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const nonce = this.uuidv1 ();
+ const request = {
+ 'nonce': nonce,
+ 'wallet': this.walletAddress,
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['asset'] = currency['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ // [
+ // {
+ // depositId: 'e9970cc0-eb6b-11ea-9e89-09a5ebc1f98e',
+ // asset: 'ETH',
+ // quantity: '1.00000000',
+ // txId: '0xcd4aac3171d7131cc9e795568c67938675185ac17641553ef54c8a7c294c8142',
+ // txTime: 1598865853000,
+ // confirmationTime: 1598865930231
+ // }
+ // ]
+ const method = params['method'];
+ params = this.omit (params, 'method');
+ const response = await this[method] (this.extend (request, params));
+ return this.parseTransactions (response, currency, since, limit);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'mined': 'ok',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ // fetchDeposits
+ // {
+ // depositId: 'e9970cc0-eb6b-11ea-9e89-09a5ebc1f98f',
+ // asset: 'ETH',
+ // quantity: '1.00000000',
+ // txId: '0xcd4aac3171d7131cc9e795568c67938675185ac17641553ef54c8a7c294c8142',
+ // txTime: 1598865853000,
+ // confirmationTime: 1598865930231
+ // }
+ // fetchWithdrwalas
+ // {
+ // withdrawalId: 'a62d8760-ec4d-11ea-9fa6-47904c19499b',
+ // asset: 'ETH',
+ // assetContractAddress: '0x0000000000000000000000000000000000000000',
+ // quantity: '0.20000000',
+ // time: 1598962883288,
+ // fee: '0.00024000',
+ // txId: '0x305e9cdbaa85ad029f50578d13d31d777c085de573ed5334d95c19116d8c03ce',
+ // txStatus: 'mined'
+ // }
+ let type = undefined;
+ if ('depositId' in transaction) {
+ type = 'deposit';
+ } else if ('withdrawalId' in transaction) {
+ type = 'withdrawal';
+ }
+ const id = this.safeString2 (transaction, 'depositId', 'withdrawId');
+ const code = this.safeCurrencyCode (this.safeString (transaction, 'asset'), currency);
+ const amount = this.safeFloat (transaction, 'quantity');
+ const txid = this.safeString (transaction, 'txId');
+ const timestamp = this.safeInteger (transaction, 'txTime');
+ let fee = undefined;
+ if ('fee' in transaction) {
+ fee = {
+ 'cost': this.safeFloat (transaction, 'fee'),
+ 'currency': 'ETH',
+ };
+ }
+ const rawStatus = this.safeString (transaction, 'txStatus');
+ const status = this.parseTransactionStatus (rawStatus);
+ const updated = this.safeInteger (transaction, 'confirmationTime');
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'address': undefined,
+ 'tag': undefined,
+ 'type': type,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': updated,
+ 'fee': fee,
};
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- body = this.json (params); // all methods are POST
- const url = this.urls['api'] + '/' + path;
+ const version = this.safeString (this.options, 'version', 'v1');
+ let url = this.urls['api'][api] + '/' + version + '/' + path;
+ const keys = Object.keys (params);
+ const length = keys.length;
+ let query = undefined;
+ if (length > 0) {
+ if (method === 'GET') {
+ query = this.urlencode (params);
+ url = url + '?' + query;
+ } else {
+ body = this.json (params);
+ }
+ }
headers = {
'Content-Type': 'application/json',
- 'Accept': 'application/json',
};
+ if (this.apiKey !== undefined) {
+ headers['IDEX-API-Key'] = this.apiKey;
+ }
if (api === 'private') {
- this.checkRequiredCredentials ();
- headers['API-Key'] = this.apiKey;
+ let payload = undefined;
+ if (method === 'GET') {
+ payload = query;
+ } else {
+ payload = body;
+ }
+ headers['IDEX-HMAC-Signature'] = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'hex');
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
-
- getIdexCreateOrderHash (order) {
- return this.soliditySha3 ([
- order['contractAddress'], // address
- order['tokenBuy'], // address
- order['amountBuy'], // uint256
- order['tokenSell'], // address
- order['amountSell'], // uint256
- order['expires'], // uint256
- order['nonce'], // uint256
- order['address'], // address
- ]);
- }
-
- getIdexCancelOrderHash (order) {
- return this.soliditySha3 ([
- order['orderHash'], // address
- order['nonce'], // uint256
- ]);
- }
-
- getIdexMarketOrderHash (order) {
- return this.soliditySha3 ([
- order['orderHash'], // address
- order['amount'], // uint256
- order['address'], // address
- order['nonce'], // uint256
- ]);
- }
-
- getIdexWithdrawHash (request) {
- return this.soliditySha3 ([
- request['contractAddress'], // address
- request['token'], // uint256
- request['amount'], // uint256
- request['address'], // address
- request['nonce'], // uint256
- ]);
- }
-
- handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
- if (response === undefined) {
- return;
- }
- if ('error' in response) {
- if (response['error'] in this.exceptions) {
- throw new this.exceptions[response['error']] (this.id + ' ' + response['error']);
- }
- throw new ExchangeError (this.id + ' ' + body);
- }
- }
};
-},{"./base/Exchange":7,"./base/errors":9}],96:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],96:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -65186,10 +76813,21 @@ module.exports = class independentreserve extends Exchange {
'countries': [ 'AU', 'NZ' ], // Australia, New Zealand
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/30521662-cf3f477c-9bcb-11e7-89bc-d1ac85012eda.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87182090-1e9e9080-c2ec-11ea-8e49-563db9a38f37.jpg',
'api': {
'public': 'https://api.independentreserve.com/Public',
'private': 'https://api.independentreserve.com/Private',
@@ -65349,6 +76987,8 @@ module.exports = class independentreserve extends Exchange {
}
parseOrder (order, market = undefined) {
+ //
+ // fetchOrder
//
// {
// "OrderGuid": "c7347e4c-b865-4c94-8f74-d934d4b0b177",
@@ -65364,9 +77004,26 @@ module.exports = class independentreserve extends Exchange {
// "SecondaryCurrencyCode": "Usd"
// }
//
+ // fetchOpenOrders & fetchClosedOrders
+ //
+ // {
+ // "OrderGuid": "b8f7ad89-e4e4-4dfe-9ea3-514d38b5edb3",
+ // "CreatedTimestampUtc": "2020-09-08T03:04:18.616367Z",
+ // "OrderType": "LimitOffer",
+ // "Volume": 0.0005,
+ // "Outstanding": 0.0005,
+ // "Price": 113885.83,
+ // "AvgPrice": 113885.83,
+ // "Value": 56.94,
+ // "Status": "Open",
+ // "PrimaryCurrencyCode": "Xbt",
+ // "SecondaryCurrencyCode": "Usd",
+ // "FeePercent": 0.005,
+ // }
+ //
let symbol = undefined;
const baseId = this.safeString (order, 'PrimaryCurrencyCode');
- const quoteId = this.safeString (order, 'PrimaryCurrencyCode');
+ const quoteId = this.safeString (order, 'SecondaryCurrencyCode');
let base = undefined;
let quote = undefined;
if ((baseId !== undefined) && (quoteId !== undefined)) {
@@ -65378,34 +77035,36 @@ module.exports = class independentreserve extends Exchange {
base = market['base'];
quote = market['quote'];
}
- let orderType = this.safeValue (order, 'Type');
- if (orderType.indexOf ('Market') >= 0) {
- orderType = 'market';
- } else if (orderType.indexOf ('Limit') >= 0) {
- orderType = 'limit';
- }
+ let orderType = this.safeString2 (order, 'Type', 'OrderType');
let side = undefined;
if (orderType.indexOf ('Bid') >= 0) {
side = 'buy';
} else if (orderType.indexOf ('Offer') >= 0) {
side = 'sell';
}
+ if (orderType.indexOf ('Market') >= 0) {
+ orderType = 'market';
+ } else if (orderType.indexOf ('Limit') >= 0) {
+ orderType = 'limit';
+ }
const timestamp = this.parse8601 (this.safeString (order, 'CreatedTimestampUtc'));
- let amount = this.safeFloat (order, 'VolumeOrdered');
- if (amount === undefined) {
- amount = this.safeFloat (order, 'Volume');
+ const amount = this.safeFloat2 (order, 'VolumeOrdered', 'Volume');
+ let filled = this.safeFloat (order, 'VolumeFilled');
+ let remaining = this.safeFloat (order, 'Outstanding');
+ if (filled === undefined) {
+ if ((remaining !== undefined) && (amount !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ }
+ if (remaining === undefined) {
+ if ((filled !== undefined) && (amount !== undefined)) {
+ remaining = Math.max (0, amount - filled);
+ }
}
- const filled = this.safeFloat (order, 'VolumeFilled');
- let remaining = undefined;
const feeRate = this.safeFloat (order, 'FeePercent');
let feeCost = undefined;
- if (amount !== undefined) {
- if (filled !== undefined) {
- remaining = amount - filled;
- if (feeRate !== undefined) {
- feeCost = feeRate * filled;
- }
- }
+ if (feeRate !== undefined) {
+ feeCost = feeRate * filled;
}
const fee = {
'rate': feeRate,
@@ -65426,8 +77085,10 @@ module.exports = class independentreserve extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': orderType,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -65464,6 +77125,44 @@ module.exports = class independentreserve extends Exchange {
return this.parseOrder (response, market);
}
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = this.ordered ({});
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['primaryCurrencyCode'] = market['baseId'];
+ request['secondaryCurrencyCode'] = market['quoteId'];
+ }
+ if (limit === undefined) {
+ limit = 50;
+ }
+ request['pageIndex'] = 1;
+ request['pageSize'] = limit;
+ const response = await this.privatePostGetOpenOrders (this.extend (request, params));
+ const data = this.safeValue (response, 'Data', []);
+ return this.parseOrders (data, market, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = this.ordered ({});
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['primaryCurrencyCode'] = market['baseId'];
+ request['secondaryCurrencyCode'] = market['quoteId'];
+ }
+ if (limit === undefined) {
+ limit = 50;
+ }
+ request['pageIndex'] = 1;
+ request['pageSize'] = limit;
+ const response = await this.privatePostGetClosedOrders (this.extend (request, params));
+ const data = this.safeValue (response, 'Data', []);
+ return this.parseOrders (data, market, since, limit);
+ }
+
async fetchMyTrades (symbol = undefined, since = undefined, limit = 50, params = {}) {
await this.loadMarkets ();
const pageIndex = this.safeInteger (params, 'pageIndex', 1);
@@ -65603,7 +77302,7 @@ module.exports = class independentreserve extends Exchange {
}
};
-},{"./base/Exchange":7}],97:[function(require,module,exports){
+},{"./base/Exchange":5}],97:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -65620,31 +77319,41 @@ module.exports = class indodax extends Exchange {
'name': 'INDODAX',
'countries': [ 'ID' ], // Indonesia
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createMarketOrder': false,
- 'fetchTickers': false,
- 'fetchOrder': true,
- 'fetchOrders': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchOpenOrders': true,
- 'fetchMyTrades': false,
'fetchCurrencies': false,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': false,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchTicker': true,
+ 'fetchTickers': false,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'withdraw': true,
},
- 'version': '1.8', // as of 9 April 2018
+ 'version': '2.0', // as of 9 April 2018
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/37443283-2fddd0e4-281c-11e8-9741-b4f1419001b5.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87070508-9358c880-c221-11ea-8dc5-5391afbbb422.jpg',
'api': {
'public': 'https://indodax.com/api',
'private': 'https://indodax.com/tapi',
},
'www': 'https://www.indodax.com',
- 'doc': 'https://indodax.com/downloads/BITCOINCOID-API-DOCUMENTATION.pdf',
+ 'doc': 'https://github.com/btcid/indodax-official-api-docs',
'referral': 'https://indodax.com/ref/testbitcoincoid/1',
},
'api': {
'public': {
'get': [
+ 'server_time',
+ 'pairs',
'{pair}/ticker',
'{pair}/trades',
'{pair}/depth',
@@ -65664,81 +77373,6 @@ module.exports = class indodax extends Exchange {
],
},
},
- 'markets': {
- // HARDCODING IS DEPRECATED
- // but they don't have a corresponding endpoint in their API
- // IDR markets
- 'BTC/IDR': { 'id': 'btc_idr', 'symbol': 'BTC/IDR', 'base': 'BTC', 'quote': 'IDR', 'baseId': 'btc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.0001, 'max': undefined }}},
- 'TEN/IDR': { 'id': 'ten_idr', 'symbol': 'TEN/IDR', 'base': 'TEN', 'quote': 'IDR', 'baseId': 'ten', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'ABYSS/IDR': { 'id': 'abyss_idr', 'symbol': 'ABYSS/IDR', 'base': 'ABYSS', 'quote': 'IDR', 'baseId': 'abyss', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'ACT/IDR': { 'id': 'act_idr', 'symbol': 'ACT/IDR', 'base': 'ACT', 'quote': 'IDR', 'baseId': 'act', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'ADA/IDR': { 'id': 'ada_idr', 'symbol': 'ADA/IDR', 'base': 'ADA', 'quote': 'IDR', 'baseId': 'ada', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'AOA/IDR': { 'id': 'aoa_idr', 'symbol': 'AOA/IDR', 'base': 'AOA', 'quote': 'IDR', 'baseId': 'aoa', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'ATOM/IDR': { 'id': 'atom_idr', 'symbol': 'ATOM/IDR', 'base': 'ATOM', 'quote': 'IDR', 'baseId': 'atom', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'BAT/IDR': { 'id': 'bat_idr', 'symbol': 'BAT/IDR', 'base': 'BAT', 'quote': 'IDR', 'baseId': 'bat', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'BCD/IDR': { 'id': 'bcd_idr', 'symbol': 'BCD/IDR', 'base': 'BCD', 'quote': 'IDR', 'baseId': 'bcd', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'BCH/IDR': { 'id': 'bchabc_idr', 'symbol': 'BCH/IDR', 'base': 'BCH', 'quote': 'IDR', 'baseId': 'bchabc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.001, 'max': undefined }}},
- 'BSV/IDR': { 'id': 'bchsv_idr', 'symbol': 'BSV/IDR', 'base': 'BSV', 'quote': 'IDR', 'baseId': 'bchsv', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.001, 'max': undefined }}},
- 'BNB/IDR': { 'id': 'bnb_idr', 'symbol': 'BNB/IDR', 'base': 'BNB', 'quote': 'IDR', 'baseId': 'bnb', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.001, 'max': undefined }}},
- 'BTG/IDR': { 'id': 'btg_idr', 'symbol': 'BTG/IDR', 'base': 'BTG', 'quote': 'IDR', 'baseId': 'btg', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'BTS/IDR': { 'id': 'bts_idr', 'symbol': 'BTS/IDR', 'base': 'BTS', 'quote': 'IDR', 'baseId': 'bts', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'BTT/IDR': { 'id': 'btt_idr', 'symbol': 'BTT/IDR', 'base': 'BTT', 'quote': 'IDR', 'baseId': 'btt', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1000, 'max': undefined }}},
- 'COAL/IDR': { 'id': 'coal_idr', 'symbol': 'COAL/IDR', 'base': 'COAL', 'quote': 'IDR', 'baseId': 'coal', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 50, 'max': undefined }}},
- 'CRO/IDR': { 'id': 'cro_idr', 'symbol': 'CRO/IDR', 'base': 'CRO', 'quote': 'IDR', 'baseId': 'cro', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'DASH/IDR': { 'id': 'drk_idr', 'symbol': 'DASH/IDR', 'base': 'DASH', 'quote': 'IDR', 'baseId': 'drk', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'DAX/IDR': { 'id': 'dax_idr', 'symbol': 'DAX/IDR', 'base': 'DAX', 'quote': 'IDR', 'baseId': 'dax', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'DOGE/IDR': { 'id': 'doge_idr', 'symbol': 'DOGE/IDR', 'base': 'DOGE', 'quote': 'IDR', 'baseId': 'doge', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1000, 'max': undefined }}},
- 'ETH/IDR': { 'id': 'eth_idr', 'symbol': 'ETH/IDR', 'base': 'ETH', 'quote': 'IDR', 'baseId': 'eth', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'EOS/IDR': { 'id': 'eos_idr', 'symbol': 'EOS/IDR', 'base': 'EOS', 'quote': 'IDR', 'baseId': 'eos', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'ETC/IDR': { 'id': 'etc_idr', 'symbol': 'ETC/IDR', 'base': 'ETC', 'quote': 'IDR', 'baseId': 'etc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'GARD/IDR': { 'id': 'gard_idr', 'symbol': 'GARD/IDR', 'base': 'GARD', 'quote': 'IDR', 'baseId': 'gard', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'GSC/IDR': { 'id': 'gsc_idr', 'symbol': 'GSC/IDR', 'base': 'GSC', 'quote': 'IDR', 'baseId': 'gsc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'GXC/IDR': { 'id': 'gxs_idr', 'symbol': 'GXC/IDR', 'base': 'GXC', 'quote': 'IDR', 'baseId': 'gxs', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'HPB/IDR': { 'id': 'hpb_idr', 'symbol': 'HPB/IDR', 'base': 'HPB', 'quote': 'IDR', 'baseId': 'hpb', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'IGNIS/IDR': { 'id': 'ignis_idr', 'symbol': 'IGNIS/IDR', 'base': 'IGNIS', 'quote': 'IDR', 'baseId': 'ignis', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'INX/IDR': { 'id': 'inx_idr', 'symbol': 'INX/IDR', 'base': 'INX', 'quote': 'IDR', 'baseId': 'inx', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'IOTA/IDR': { 'id': 'iota_idr', 'symbol': 'IOTA/IDR', 'base': 'IOTA', 'quote': 'IDR', 'baseId': 'iota', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'LINK/IDR': { 'id': 'link_idr', 'symbol': 'LINK/IDR', 'base': 'LINK', 'quote': 'IDR', 'baseId': 'link', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'LTC/IDR': { 'id': 'ltc_idr', 'symbol': 'LTC/IDR', 'base': 'LTC', 'quote': 'IDR', 'baseId': 'ltc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'MBL/IDR': { 'id': 'mbl_idr', 'symbol': 'MBL/IDR', 'base': 'MBL', 'quote': 'IDR', 'baseId': 'mbl', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'NEO/IDR': { 'id': 'neo_idr', 'symbol': 'NEO/IDR', 'base': 'NEO', 'quote': 'IDR', 'baseId': 'neo', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'NPXS/IDR': { 'id': 'npxs_idr', 'symbol': 'NPXS/IDR', 'base': 'NPXS', 'quote': 'IDR', 'baseId': 'npxs', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'NXT/IDR': { 'id': 'nxt_idr', 'symbol': 'NXT/IDR', 'base': 'NXT', 'quote': 'IDR', 'baseId': 'nxt', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'OKB/IDR': { 'id': 'okb_idr', 'symbol': 'OKB/IDR', 'base': 'OKB', 'quote': 'IDR', 'baseId': 'okb', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.5, 'max': undefined }}},
- 'ONT/IDR': { 'id': 'ont_idr', 'symbol': 'ONT/IDR', 'base': 'ONT', 'quote': 'IDR', 'baseId': 'ont', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'PXG/IDR': { 'id': 'pxg_idr', 'symbol': 'PXG/IDR', 'base': 'PXG', 'quote': 'IDR', 'baseId': 'pxg', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'QTUM/IDR': { 'id': 'qtum_idr', 'symbol': 'QTUM/IDR', 'base': 'QTUM', 'quote': 'IDR', 'baseId': 'qtum', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'RVN/IDR': { 'id': 'rvn_idr', 'symbol': 'RVN/IDR', 'base': 'RVN', 'quote': 'IDR', 'baseId': 'rvn', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'SSP/IDR': { 'id': 'ssp_idr', 'symbol': 'SSP/IDR', 'base': 'SSP', 'quote': 'IDR', 'baseId': 'ssp', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'SUMO/IDR': { 'id': 'sumo_idr', 'symbol': 'SUMO/IDR', 'base': 'SUMO', 'quote': 'IDR', 'baseId': 'sumo', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- // 'STQ/IDR': { 'id': 'stq_idr', 'symbol': 'STQ/IDR', 'base': 'STQ', 'quote': 'IDR', 'baseId': 'stq', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'TRX/IDR': { 'id': 'trx_idr', 'symbol': 'TRX/IDR', 'base': 'TRX', 'quote': 'IDR', 'baseId': 'trx', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'USDC/IDR': { 'id': 'usdc_idr', 'symbol': 'USDC/IDR', 'base': 'USDC', 'quote': 'IDR', 'baseId': 'usdc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'USDT/IDR': { 'id': 'usdt_idr', 'symbol': 'USDT/IDR', 'base': 'USDT', 'quote': 'IDR', 'baseId': 'usdt', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'VEX/IDR': { 'id': 'vex_idr', 'symbol': 'VEX/IDR', 'base': 'VEX', 'quote': 'IDR', 'baseId': 'vex', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'VIDY/IDR': { 'id': 'vidy_idr', 'symbol': 'VIDY/IDR', 'base': 'VIDY', 'quote': 'IDR', 'baseId': 'vidy', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 100, 'max': undefined }}},
- 'WAVES/IDR': { 'id': 'waves_idr', 'symbol': 'WAVES/IDR', 'base': 'WAVES', 'quote': 'IDR', 'baseId': 'waves', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'XEM/IDR': { 'id': 'nem_idr', 'symbol': 'XEM/IDR', 'base': 'XEM', 'quote': 'IDR', 'baseId': 'nem', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'XLM/IDR': { 'id': 'str_idr', 'symbol': 'XLM/IDR', 'base': 'XLM', 'quote': 'IDR', 'baseId': 'str', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 20, 'max': undefined }}},
- 'XDCE/IDR': { 'id': 'xdce_idr', 'symbol': 'XDCE/IDR', 'base': 'XDCE', 'quote': 'IDR', 'baseId': 'xdce', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 10, 'max': undefined }}},
- 'XMR/IDR': { 'id': 'xmr_idr', 'symbol': 'XMR/IDR', 'base': 'XMR', 'quote': 'IDR', 'baseId': 'xmr', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'XRP/IDR': { 'id': 'xrp_idr', 'symbol': 'XRP/IDR', 'base': 'XRP', 'quote': 'IDR', 'baseId': 'xrp', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 10, 'max': undefined }}},
- 'XZC/IDR': { 'id': 'xzc_idr', 'symbol': 'XZC/IDR', 'base': 'XZC', 'quote': 'IDR', 'baseId': 'xzc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'VSYS/IDR': { 'id': 'vsys_idr', 'symbol': 'VSYS/IDR', 'base': 'VSYS', 'quote': 'IDR', 'baseId': 'vsys', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'ZEC/IDR': { 'id': 'zec_idr', 'symbol': 'ZEC/IDR', 'base': 'ZEC', 'quote': 'IDR', 'baseId': 'zec', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- // BTC markets
- 'BTS/BTC': { 'id': 'bts_btc', 'symbol': 'BTS/BTC', 'base': 'BTS', 'quote': 'BTC', 'baseId': 'bts', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'DASH/BTC': { 'id': 'drk_btc', 'symbol': 'DASH/BTC', 'base': 'DASH', 'quote': 'BTC', 'baseId': 'drk', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 6 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'DOGE/BTC': { 'id': 'doge_btc', 'symbol': 'DOGE/BTC', 'base': 'DOGE', 'quote': 'BTC', 'baseId': 'doge', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'ETH/BTC': { 'id': 'eth_btc', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC', 'baseId': 'eth', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 5 }, 'limits': { 'amount': { 'min': 0.001, 'max': undefined }}},
- 'LTC/BTC': { 'id': 'ltc_btc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'baseId': 'ltc', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 6 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'NXT/BTC': { 'id': 'nxt_btc', 'symbol': 'NXT/BTC', 'base': 'NXT', 'quote': 'BTC', 'baseId': 'nxt', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'SUMO/BTC': { 'id': 'sumo_btc', 'symbol': 'SUMO/BTC', 'base': 'SUMO', 'quote': 'BTC', 'baseId': 'sumo', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'TEN/BTC': { 'id': 'ten_btc', 'symbol': 'TEN/BTC', 'base': 'TEN', 'quote': 'BTC', 'baseId': 'ten', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'XEM/BTC': { 'id': 'nem_btc', 'symbol': 'XEM/BTC', 'base': 'XEM', 'quote': 'BTC', 'baseId': 'nem', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'XLM/BTC': { 'id': 'str_btc', 'symbol': 'XLM/BTC', 'base': 'XLM', 'quote': 'BTC', 'baseId': 'str', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'XRP/BTC': { 'id': 'xrp_btc', 'symbol': 'XRP/BTC', 'base': 'XRP', 'quote': 'BTC', 'baseId': 'xrp', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- },
'fees': {
'trading': {
'tierBased': false,
@@ -65760,9 +77394,121 @@ module.exports = class indodax extends Exchange {
'Minimum order': InvalidOrder,
},
},
+ // exchange-specific options
+ 'options': {
+ 'recvWindow': 5 * 1000, // default 5 sec
+ 'timeDifference': 0, // the difference between system clock and exchange clock
+ 'adjustForTimeDifference': false, // controls the adjustment logic upon instantiation
+ },
+ 'commonCurrencies': {
+ 'STR': 'XLM',
+ 'BCHABC': 'BCH',
+ 'BCHSV': 'BSV',
+ 'DRK': 'DASH',
+ 'NEM': 'XEM',
+ },
});
}
+ nonce () {
+ return this.milliseconds () - this.options['timeDifference'];
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetServerTime (params);
+ //
+ // {
+ // "timezone": "UTC",
+ // "server_time": 1571205969552
+ // }
+ //
+ return this.safeInteger (response, 'server_time');
+ }
+
+ async loadTimeDifference (params = {}) {
+ const serverTime = await this.fetchTime (params);
+ const after = this.milliseconds ();
+ this.options['timeDifference'] = after - serverTime;
+ return this.options['timeDifference'];
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetPairs (params);
+ //
+ // [
+ // {
+ // "id": "btcidr",
+ // "symbol": "BTCIDR",
+ // "base_currency": "idr",
+ // "traded_currency": "btc",
+ // "traded_currency_unit": "BTC",
+ // "description": "BTC/IDR",
+ // "ticker_id": "btc_idr",
+ // "volume_precision": 0,
+ // "price_precision": 1000,
+ // "price_round": 8,
+ // "pricescale": 1000,
+ // "trade_min_base_currency": 10000,
+ // "trade_min_traded_currency": 0.00007457,
+ // "has_memo": false,
+ // "memo_name": false,
+ // "has_payment_id": false,
+ // "trade_fee_percent": 0.3,
+ // "url_logo": "https://indodax.com/v2/logo/svg/color/btc.svg",
+ // "url_logo_png": "https://indodax.com/v2/logo/png/color/btc.png",
+ // "is_maintenance": 0
+ // }
+ // ]
+ //
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ const id = this.safeString (market, 'ticker_id');
+ const baseId = this.safeString (market, 'traded_currency');
+ const quoteId = this.safeString (market, 'base_currency');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const taker = this.safeFloat (market, 'trade_fee_percent');
+ const isMaintenance = this.safeInteger (market, 'is_maintenance');
+ const active = (isMaintenance) ? false : true;
+ const pricePrecision = this.safeInteger (market, 'price_round');
+ const precision = {
+ 'amount': 8,
+ 'price': pricePrecision,
+ };
+ const limits = {
+ 'amount': {
+ 'min': this.safeFloat (market, 'trade_min_traded_currency'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': this.safeFloat (market, 'trade_min_base_currency'),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ };
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'taker': taker,
+ 'percentage': true,
+ 'precision': precision,
+ 'limits': limits,
+ 'info': market,
+ 'active': active,
+ });
+ }
+ return result;
+ }
+
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.privatePostGetInfo (params);
@@ -65885,6 +77631,15 @@ module.exports = class indodax extends Exchange {
return this.parseTrades (response, market, since, limit);
}
+ parseOrderStatus (status) {
+ const statuses = {
+ 'open': 'open',
+ 'filled': 'closed',
+ 'cancelled': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
parseOrder (order, market = undefined) {
//
// {
@@ -65900,12 +77655,7 @@ module.exports = class indodax extends Exchange {
if ('type' in order) {
side = order['type'];
}
- let status = this.safeString (order, 'status', 'open');
- if (status === 'filled') {
- status = 'closed';
- } else if (status === 'cancelled') {
- status = 'canceled';
- }
+ const status = this.parseOrderStatus (this.safeString (order, 'status', 'open'));
let symbol = undefined;
let cost = undefined;
const price = this.safeFloat (order, 'price');
@@ -65953,8 +77703,10 @@ module.exports = class indodax extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -66025,12 +77777,9 @@ module.exports = class indodax extends Exchange {
request['pair'] = market['id'];
}
const response = await this.privatePostOrderHistory (this.extend (request, params));
- let orders = this.parseOrders (response['return']['orders'], market, since, limit);
+ let orders = this.parseOrders (response['return']['orders'], market);
orders = this.filterBy (orders, 'status', 'closed');
- if (symbol !== undefined) {
- return this.filterBySymbol (orders, symbol);
- }
- return orders;
+ return this.filterBySymbolSinceLimit (orders, symbol, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
@@ -66052,9 +77801,11 @@ module.exports = class indodax extends Exchange {
}
request[currency] = amount;
const result = await this.privatePostTrade (this.extend (request, params));
+ const data = this.safeValue (result, 'return', {});
+ const id = this.safeString (data, 'order_id');
return {
'info': result,
- 'id': result['return']['order_id'].toString (),
+ 'id': id,
};
}
@@ -66130,7 +77881,8 @@ module.exports = class indodax extends Exchange {
this.checkRequiredCredentials ();
body = this.urlencode (this.extend ({
'method': path,
- 'nonce': this.nonce (),
+ 'timestamp': this.nonce (),
+ 'recvWindow': this.options['recvWindow'],
}, params));
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
@@ -66170,7 +77922,7 @@ module.exports = class indodax extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],98:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],98:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -66189,9 +77941,20 @@ module.exports = class itbit extends Exchange {
'rateLimit': 2000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': true,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27822159-66153620-60ad-11e7-89e7-005f6d7f3de0.jpg',
@@ -66240,6 +78003,9 @@ module.exports = class itbit extends Exchange {
'ETH/USD': { 'id': 'ETHUSD', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD', 'baseId': 'ETH', 'quoteId': 'USD' },
'ETH/EUR': { 'id': 'ETHEUR', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR', 'baseId': 'ETH', 'quoteId': 'EUR' },
'ETH/SGD': { 'id': 'ETHSGD', 'symbol': 'ETH/SGD', 'base': 'ETH', 'quote': 'SGD', 'baseId': 'ETH', 'quoteId': 'SGD' },
+ 'PAXGUSD': { 'id': 'PAXGUSD', 'symbol': 'PAXG/USD', 'base': 'PAXG', 'quote': 'USD', 'baseId': 'PAXG', 'quoteId': 'USD' },
+ 'BCHUSD': { 'id': 'BCHUSD', 'symbol': 'BCH/USD', 'base': 'BCH', 'quote': 'USD', 'baseId': 'BCH', 'quoteId': 'USD' },
+ 'LTCUSD': { 'id': 'LTCUSD', 'symbol': 'LTC/USD', 'base': 'LTC', 'quote': 'USD', 'baseId': 'LTC', 'quoteId': 'USD' },
},
'fees': {
'trading': {
@@ -66698,8 +78464,10 @@ module.exports = class itbit extends Exchange {
'status': this.parseOrderStatus (this.safeString (order, 'status')),
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -66788,7 +78556,7 @@ module.exports = class itbit extends Exchange {
const binhash = this.binaryConcat (binaryUrl, hash);
const signature = this.hmac (binhash, this.encode (this.secret), 'sha512', 'base64');
headers = {
- 'Authorization': this.apiKey + ':' + this.decode (signature),
+ 'Authorization': this.apiKey + ':' + signature,
'Content-Type': 'application/json',
'X-Auth-Timestamp': timestamp,
'X-Auth-Nonce': nonce,
@@ -66806,599 +78574,13 @@ module.exports = class itbit extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],99:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],99:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ArgumentsRequired, InvalidOrder, OrderNotFound } = require ('./base/errors');
-
-// ---------------------------------------------------------------------------
-
-module.exports = class kkex extends Exchange {
- describe () {
- return this.deepExtend (super.describe (), {
- 'id': 'kkex',
- 'name': 'KKEX',
- 'countries': [ 'CN', 'US', 'JP' ],
- 'version': 'v2',
- 'has': {
- 'CORS': false,
- 'fetchBalance': true,
- 'fetchTickers': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'fetchMyTrades': true,
- 'fetchOHLCV': true,
- 'createMarketOrder': true,
- 'fetchOrder': true,
- },
- 'timeframes': {
- '1m': '1min',
- '5m': '5min',
- '15m': '15min',
- '30m': '30min',
- '1h': '1hour',
- '4h': '4hour',
- '12h': '12hour',
- '1d': '1day',
- '1w': '1week',
- '1M': '1month',
- },
- 'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/47401462-2e59f800-d74a-11e8-814f-e4ae17b4968a.jpg',
- 'api': {
- 'public': 'https://kkex.com/api/v1',
- 'private': 'https://kkex.com/api/v2',
- 'v1': 'https://kkex.com/api/v1',
- },
- 'www': 'https://kkex.com',
- 'doc': 'https://kkex.com/api_wiki/cn/',
- 'fees': 'https://intercom.help/kkex/fee',
- },
- 'api': {
- 'public': {
- 'get': [
- 'exchange_rate',
- 'products',
- 'assets',
- 'tickers',
- 'ticker',
- 'depth',
- 'trades',
- 'kline',
- ],
- },
- 'private': {
- 'post': [
- 'profile',
- 'trade',
- 'batch_trade',
- 'cancel_order',
- 'cancel_all_orders',
- 'order_history',
- 'userinfo',
- 'order_info',
- 'orders_info',
- ],
- },
- 'v1': {
- 'post': [
- 'process_strategy',
- ],
- },
- },
- 'fees': {
- 'trading': {
- 'tierBased': false,
- 'percentage': true,
- 'taker': 0.002,
- 'maker': 0.002,
- },
- 'funding': {
- 'tierBased': false,
- 'percentage': false,
- 'withdraw': {},
- 'deposit': {},
- },
- },
- 'options': {
- 'lastNonceTimestamp': 0,
- },
- });
- }
-
- async fetchMarkets (params = {}) {
- let tickers = await this.publicGetTickers (params);
- tickers = tickers['tickers'];
- let products = await this.publicGetProducts (params);
- products = products['products'];
- const markets = [];
- for (let k = 0; k < tickers.length; k++) {
- const keys = Object.keys (tickers[k]);
- markets.push (keys[0]);
- }
- const result = [];
- for (let i = 0; i < markets.length; i++) {
- const id = markets[i];
- const market = markets[i];
- let baseId = '';
- let quoteId = '';
- let precision = {};
- let limits = {};
- for (let j = 0; j < products.length; j++) {
- const p = products[j];
- if (p['mark_asset'] + p['base_asset'] === market) {
- quoteId = p['base_asset'];
- baseId = p['mark_asset'];
- const price_scale_str = p['price_scale'].toString ();
- const scale = price_scale_str.length - 1;
- precision = {
- 'price': scale,
- 'amount': scale,
- };
- limits = {
- 'amount': {
- 'min': Math.max (this.safeFloat (p, 'min_bid_size'), this.safeFloat (p, 'min_ask_size')),
- 'max': Math.min (this.safeFloat (p, 'max_bid_size'), this.safeFloat (p, 'max_ask_size')),
- },
- 'price': {
- 'min': this.safeFloat (p, 'min_price'),
- 'max': this.safeFloat (p, 'max_price'),
- },
- };
- limits['cost'] = {
- 'min': this.safeFloat (p, 'min_bid_amount'),
- 'max': this.safeFloat (p, 'max_bid_amount'),
- };
- }
- }
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- const symbol = base + '/' + quote;
- result.push ({
- 'id': id,
- 'symbol': symbol,
- 'base': base,
- 'quote': quote,
- 'baseId': baseId,
- 'quoteId': quoteId,
- 'active': true,
- 'precision': precision,
- 'limits': limits,
- 'info': market,
- });
- }
- return result;
- }
-
- parseTicker (ticker, market = undefined) {
- const timestamp = this.safeTimestamp (ticker, 'date');
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- const last = this.safeFloat (ticker, 'last');
- return {
- 'symbol': symbol,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'high': this.safeFloat (ticker, 'high'),
- 'low': this.safeFloat (ticker, 'low'),
- 'bid': this.safeFloat (ticker, 'buy'),
- 'bidVolume': undefined,
- 'ask': this.safeFloat (ticker, 'sell'),
- 'askVolume': undefined,
- 'vwap': undefined,
- 'open': undefined,
- 'close': last,
- 'last': last,
- 'previousClose': undefined,
- 'change': undefined,
- 'percentage': undefined,
- 'average': undefined,
- 'baseVolume': this.safeFloat (ticker, 'vol'),
- 'quoteVolume': undefined,
- 'info': ticker,
- };
- }
-
- async fetchTicker (symbol, params = {}) {
- await this.loadMarkets ();
- const market = this.markets[symbol];
- const request = {
- 'symbol': market['id'],
- };
- const response = await this.publicGetTicker (this.extend (request, params));
- const ticker = this.extend (response['ticker'], this.omit (response, 'ticker'));
- return this.parseTicker (ticker, market);
- }
-
- async fetchTickers (symbols = undefined, params = {}) {
- await this.loadMarkets ();
- const response = await this.publicGetTickers (params);
- //
- // { date: 1540350657,
- // tickers: [ { ENUBTC: { sell: "0.00000256",
- // buy: "0.00000253",
- // last: "0.00000253",
- // vol: "138686.828804",
- // high: "0.00000278",
- // low: "0.00000253",
- // open: "0.0000027" } },
- // { ENUEOS: { sell: "0.00335",
- // buy: "0.002702",
- // last: "0.0034",
- // vol: "15084.9",
- // high: "0.0034",
- // low: "0.003189",
- // open: "0.003189" } } ],
- // result: true }
- //
- const tickers = this.safeValue (response, 'tickers');
- const result = {};
- for (let i = 0; i < tickers.length; i++) {
- const ids = Object.keys (tickers[i]);
- const id = ids[0];
- const market = this.safeValue (this.markets_by_id, id);
- if (market !== undefined) {
- const symbol = market['symbol'];
- const ticker = this.extend (tickers[i][id], this.omit (response, 'tickers'));
- result[symbol] = this.parseTicker (ticker, market);
- }
- }
- return result;
- }
-
- async fetchOrderBook (symbol, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'symbol': this.marketId (symbol),
- };
- if (limit !== undefined) {
- request['size'] = limit;
- }
- const response = await this.publicGetDepth (this.extend (request, params));
- return this.parseOrderBook (response);
- }
-
- parseTrade (trade, market = undefined) {
- const timestamp = this.safeInteger (trade, 'date_ms');
- const datetime = this.iso8601 (timestamp);
- const price = this.safeFloat (trade, 'price');
- const amount = this.safeFloat (trade, 'amount');
- let cost = undefined;
- if (price !== undefined) {
- if (amount !== undefined) {
- cost = amount * price;
- }
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- const id = this.safeString (trade, 'tid');
- const type = undefined;
- const side = this.safeString (trade, 'type');
- return {
- 'info': trade,
- 'id': id,
- 'timestamp': timestamp,
- 'datetime': datetime,
- 'symbol': symbol,
- 'order': undefined,
- 'type': type,
- 'side': side,
- 'takerOrMaker': undefined,
- 'price': price,
- 'amount': amount,
- 'cost': cost,
- 'fee': undefined,
- };
- }
-
- async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'symbol': market['id'],
- };
- const response = await this.publicGetTrades (this.extend (request, params));
- return this.parseTrades (response, market, since, limit);
- }
-
- async fetchBalance (params = {}) {
- await this.loadMarkets ();
- const response = await this.privatePostUserinfo (params);
- const balances = this.safeValue (response, 'info');
- const result = { 'info': response };
- const funds = this.safeValue (balances, 'funds');
- const free = this.safeValue (funds, 'free', {});
- const freezed = this.safeValue (funds, 'freezed', {});
- const currencyIds = Object.keys (free);
- for (let i = 0; i < currencyIds.length; i++) {
- const currencyId = currencyIds[i];
- const code = this.safeCurrencyCode (currencyId);
- const account = this.account ();
- account['free'] = this.safeFloat (free, currencyId);
- account['used'] = this.safeFloat (freezed, currencyId);
- result[code] = account;
- }
- return this.parseBalance (result);
- }
-
- async fetchOrder (id, symbol = undefined, params = {}) {
- if (!symbol) {
- throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
- }
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'order_id': id,
- 'symbol': market['id'],
- };
- const response = await this.privatePostOrderInfo (this.extend (request, params));
- if (response['result']) {
- return this.parseOrder (response['order'], market);
- }
- throw new OrderNotFound (this.id + ' order ' + id + ' not found');
- }
-
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
- return [
- parseInt (ohlcv[0]),
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
- parseFloat (ohlcv[5]),
- ];
- }
-
- async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'symbol': market['id'],
- 'type': this.timeframes[timeframe],
- };
- if (since !== undefined) {
- // since = this.milliseconds () - this.parseTimeframe (timeframe) * limit * 1000;
- request['since'] = parseInt (since / 1000);
- }
- if (limit !== undefined) {
- request['size'] = limit;
- }
- const response = await this.publicGetKline (this.extend (request, params));
- //
- // [
- // [
- // "1521072000000",
- // "0.000002",
- // "0.00003",
- // "0.000002",
- // "0.00003",
- // "3.106889"
- // ],
- // [
- // "1517356800000",
- // "0.1",
- // "0.1",
- // "0.00000013",
- // "0.000001",
- // "542832.83114"
- // ]
- // ]
- //
- return this.parseOHLCVs (response, market, timeframe, since, limit);
- }
-
- parseOrderStatus (status) {
- const statuses = {
- '-1': 'canceled',
- '0': 'open',
- '1': 'open',
- '2': 'closed',
- '3': 'open',
- '4': 'canceled',
- };
- return this.safeString (statuses, status, status);
- }
-
- parseOrder (order, market = undefined) {
- //
- // {
- // "status": 2,
- // "source": "NORMAL",
- // "amount": "10.852019",
- // "create_date": 1523938461036,
- // "avg_price": "0.00096104",
- // "order_id": "100",
- // "price": "0.00096105",
- // "type": "buy",
- // "symbol": "READBTC",
- // "deal_amount": "10.852019"
- // }
- //
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- let side = this.safeString (order, 'side');
- if (side === undefined) {
- side = this.safeString (order, 'type');
- }
- const timestamp = this.safeInteger (order, 'create_date');
- const id = this.safeString2 (order, 'order_id', 'id');
- const status = this.parseOrderStatus (this.safeString (order, 'status'));
- const price = this.safeFloat (order, 'price');
- const amount = this.safeFloat (order, 'amount');
- const filled = this.safeFloat (order, 'deal_amount');
- let average = this.safeFloat (order, 'avg_price');
- average = this.safeFloat (order, 'price_avg', average);
- let remaining = undefined;
- let cost = undefined;
- if (filled !== undefined) {
- if (amount !== undefined) {
- remaining = amount - filled;
- }
- if (average !== undefined) {
- cost = average * filled;
- }
- }
- return {
- 'id': id,
- 'clientOrderId': undefined,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'lastTradeTimestamp': undefined,
- 'status': status,
- 'symbol': symbol,
- 'average': average,
- 'type': 'limit',
- 'side': side,
- 'price': price,
- 'cost': cost,
- 'amount': amount,
- 'filled': filled,
- 'remaining': remaining,
- 'fee': undefined,
- 'info': order,
- 'trades': undefined,
- };
- }
-
- async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'symbol': market['id'],
- 'type': side,
- };
- if (type === 'market') {
- // for market buy it requires the amount of quote currency to spend
- if (side === 'buy') {
- if (this.options['createMarketBuyOrderRequiresPrice']) {
- if (price === undefined) {
- throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false to supply the cost in the amount argument (the exchange-specific behaviour)");
- } else {
- request['amount'] = this.costToPrecision (symbol, parseFloat (amount) * parseFloat (price));
- }
- }
- request['price'] = this.costToPrecision (symbol, amount);
- } else {
- request['amount'] = this.amountToPrecision (symbol, amount);
- }
- request['type'] += '_' + type;
- } else {
- request['amount'] = this.amountToPrecision (symbol, amount);
- request['price'] = this.priceToPrecision (symbol, price);
- }
- const response = await this.privatePostTrade (this.extend (request, params));
- const id = this.safeString (response, 'order_id');
- return {
- 'info': response,
- 'id': id,
- 'datetime': undefined,
- 'timestamp': undefined,
- 'lastTradeTimestamp': undefined,
- 'status': 'open',
- 'symbol': symbol,
- 'type': type,
- 'side': side,
- 'price': price,
- 'cost': undefined,
- 'amount': amount,
- 'filled': undefined,
- 'remaining': undefined,
- 'trades': undefined,
- 'fee': undefined,
- 'clientOrderId': undefined,
- 'average': undefined,
- };
- }
-
- async cancelOrder (id, symbol = undefined, params = {}) {
- if (symbol === undefined) {
- throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
- }
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'order_id': id,
- 'symbol': market['id'],
- };
- return await this.privatePostCancelOrder (this.extend (request, params));
- }
-
- async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'symbol': market['id'],
- };
- if (limit !== undefined) {
- request['page_length'] = limit; // 20 by default
- }
- const response = await this.privatePostOrderHistory (this.extend (request, params));
- return this.parseOrders (response['orders'], market, since, limit);
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const request = {
- 'status': 0,
- };
- return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
- }
-
- async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const request = {
- 'status': 1,
- };
- return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
- }
-
- nonce () {
- return this.milliseconds ();
- }
-
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- let url = this.urls['api'][api] + '/' + path;
- if (api === 'public') {
- url += '?' + this.urlencode (params);
- headers = { 'Content-Type': 'application/json' };
- } else {
- this.checkRequiredCredentials ();
- const nonce = this.nonce ();
- let signature = this.extend ({
- 'nonce': nonce,
- 'api_key': this.apiKey,
- }, params);
- signature = this.urlencode (this.keysort (signature));
- signature += '&secret_key=' + this.secret;
- signature = this.hash (this.encode (signature), 'md5');
- signature = signature.toUpperCase ();
- body = this.extend ({
- 'api_key': this.apiKey,
- 'sign': signature,
- 'nonce': nonce,
- }, params);
- body = this.urlencode (body);
- headers = { 'Content-Type': 'application/x-www-form-urlencoded' };
- }
- return { 'url': url, 'method': method, 'body': body, 'headers': headers };
- }
-};
-
-},{"./base/Exchange":7,"./base/errors":9}],100:[function(require,module,exports){
-'use strict';
-
-// ---------------------------------------------------------------------------
-
-const Exchange = require ('./base/Exchange');
-const { BadSymbol, ExchangeNotAvailable, ArgumentsRequired, PermissionDenied, AuthenticationError, ExchangeError, OrderNotFound, DDoSProtection, InvalidNonce, InsufficientFunds, CancelPending, InvalidOrder, InvalidAddress, NotSupported } = require ('./base/errors');
+const { BadSymbol, ExchangeNotAvailable, ArgumentsRequired, PermissionDenied, AuthenticationError, ExchangeError, OrderNotFound, DDoSProtection, InvalidNonce, InsufficientFunds, CancelPending, InvalidOrder, InvalidAddress } = require ('./base/errors');
const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -67414,24 +78596,32 @@ module.exports = class kraken extends Exchange {
'certified': true,
'pro': true,
'has': {
+ 'cancelOrder': true,
+ 'CORS': false,
'createDepositAddress': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchLedgerEntry': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrderTrades': 'emulated',
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
- 'CORS': false,
- 'fetchCurrencies': true,
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'fetchMyTrades': true,
'fetchWithdrawals': true,
- 'fetchDeposits': true,
'withdraw': true,
- 'fetchLedgerEntry': true,
- 'fetchLedger': true,
- 'fetchOrderTrades': 'emulated',
},
'marketsByAltname': {},
'timeframes': {
@@ -67545,7 +78735,6 @@ module.exports = class kraken extends Exchange {
'get': [
// we should really refrain from putting fixed fee numbers and stop hardcoding
// we will be using their web APIs to scrape all numbers from these articles
- '205893708', // -What-is-the-minimum-order-size-
'360000292886', // -What-are-the-deposit-fees-
'201893608', // -What-are-the-withdrawal-fees-
],
@@ -67595,6 +78784,8 @@ module.exports = class kraken extends Exchange {
'commonCurrencies': {
'XBT': 'BTC',
'XDG': 'DOGE',
+ 'REPV2': 'REP',
+ 'REP': 'REPV1',
},
'options': {
'cacheDepositMethodsOnFetchDepositAddress': true, // will issue up to two calls in fetchDepositAddress
@@ -67602,7 +78793,6 @@ module.exports = class kraken extends Exchange {
'delistedMarketsById': {},
// cannot withdraw/deposit these
'inactiveCurrencies': [ 'CAD', 'USD', 'JPY', 'GBP' ],
- 'fetchMinOrderAmounts': true,
},
'exceptions': {
'EQuery:Invalid asset pair': BadSymbol, // {"error":["EQuery:Invalid asset pair"]}
@@ -67618,6 +78808,8 @@ module.exports = class kraken extends Exchange {
'EGeneral:Internal error': ExchangeNotAvailable,
'EGeneral:Temporary lockout': DDoSProtection,
'EGeneral:Permission denied': PermissionDenied,
+ 'EOrder:Unknown order': InvalidOrder,
+ 'EOrder:Order minimum not met': InvalidOrder,
},
});
}
@@ -67630,34 +78822,6 @@ module.exports = class kraken extends Exchange {
return this.decimalToPrecision (fee, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES);
}
- async fetchMinOrderAmounts (params = {}) {
- const response = await this.zendeskGet205893708 (params);
- const article = this.safeValue (response, 'article');
- const html = this.safeString (article, 'body');
- const parts = html.split (' | ');
- const numParts = parts.length;
- if (numParts < 3) {
- throw new NotSupported (this.id + ' fetchMinOrderAmounts HTML page markup has changed: https://kraken.zendesk.com/api/v2/help_center/en-us/articles/205893708');
- }
- const result = {};
- // skip the part before the header and the header itself
- for (let i = 2; i < parts.length; i++) {
- const part = parts[i];
- const chunks = part.split (' | ');
- const amountAndCode = chunks[0];
- if (amountAndCode !== 'To Be Announced') {
- const pieces = amountAndCode.split (' ');
- const numPieces = pieces.length;
- if (numPieces === 2) {
- const amount = parseFloat (pieces[0]);
- const code = this.safeCurrencyCode (pieces[1]);
- result[code] = amount;
- }
- }
- }
- return result;
- }
-
async fetchMarkets (params = {}) {
const response = await this.publicGetAssetPairs (params);
//
@@ -67701,16 +78865,12 @@ module.exports = class kraken extends Exchange {
// ],
// "fee_volume_currency":"ZUSD",
// "margin_call":80,
- // "margin_stop":40
+ // "margin_stop":40,
+ // "ordermin": "1"
// },
// }
// }
//
- const fetchMinOrderAmounts = this.safeValue (this.options, 'fetchMinOrderAmounts', false);
- let limits = {};
- if (fetchMinOrderAmounts) {
- limits = await this.fetchMinOrderAmounts ();
- }
const keys = Object.keys (response['result']);
let result = [];
for (let i = 0; i < keys.length; i++) {
@@ -67730,10 +78890,7 @@ module.exports = class kraken extends Exchange {
'amount': market['lot_decimals'],
'price': market['pair_decimals'],
};
- let minAmount = Math.pow (10, -precision['amount']);
- if (base in limits) {
- minAmount = limits[base];
- }
+ const minAmount = this.safeFloat (market, 'ordermin');
result.push ({
'id': id,
'symbol': symbol,
@@ -67970,8 +79127,8 @@ module.exports = class kraken extends Exchange {
await this.loadMarkets ();
symbols = (symbols === undefined) ? this.symbols : symbols;
const marketIds = [];
- for (let i = 0; i < this.symbols.length; i++) {
- const symbol = this.symbols[i];
+ for (let i = 0; i < symbols.length; i++) {
+ const symbol = symbols[i];
const market = this.markets[symbol];
if (market['active'] && !market['darkpool']) {
marketIds.push (market['id']);
@@ -67989,11 +79146,9 @@ module.exports = class kraken extends Exchange {
const market = this.markets_by_id[id];
const symbol = market['symbol'];
const ticker = tickers[id];
- if (this.inArray (symbol, symbols)) {
- result[symbol] = this.parseTicker (ticker, market);
- }
+ result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -68011,14 +79166,26 @@ module.exports = class kraken extends Exchange {
return this.parseTicker (ticker, market);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591475640,
+ // "0.02500",
+ // "0.02500",
+ // "0.02500",
+ // "0.02500",
+ // "0.02500",
+ // "9.12201000",
+ // 5
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
- parseFloat (ohlcv[6]),
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 6),
];
}
@@ -68033,7 +79200,21 @@ module.exports = class kraken extends Exchange {
request['since'] = parseInt ((since - 1) / 1000);
}
const response = await this.publicGetOHLC (this.extend (request, params));
- const ohlcvs = response['result'][market['id']];
+ //
+ // {
+ // "error":[],
+ // "result":{
+ // "XETHXXBT":[
+ // [1591475580,"0.02499","0.02499","0.02499","0.02499","0.00000","0.00000000",0],
+ // [1591475640,"0.02500","0.02500","0.02500","0.02500","0.02500","9.12201000",5],
+ // [1591475700,"0.02499","0.02499","0.02499","0.02499","0.02499","1.28681415",2],
+ // [1591475760,"0.02499","0.02499","0.02499","0.02499","0.02499","0.08800000",1],
+ // ],
+ // "last":1591517580
+ // }
+ // }
+ const result = this.safeValue (response, 'result', {});
+ const ohlcvs = this.safeValue (result, market['id'], []);
return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
}
@@ -68354,6 +79535,11 @@ module.exports = class kraken extends Exchange {
'ordertype': type,
'volume': this.amountToPrecision (symbol, amount),
};
+ const clientOrderId = this.safeString2 (params, 'userref', 'clientOrderId');
+ const query = this.omit (params, [ 'userref', 'clientOrderId' ]);
+ if (clientOrderId !== undefined) {
+ request['userref'] = clientOrderId;
+ }
const priceIsDefined = (price !== undefined);
const marketOrder = (type === 'market');
const limitOrder = (type === 'limit');
@@ -68361,35 +79547,18 @@ module.exports = class kraken extends Exchange {
if (shouldIncludePrice) {
request['price'] = this.priceToPrecision (symbol, price);
}
- const response = await this.privatePostAddOrder (this.extend (request, params));
- let id = this.safeValue (response['result'], 'txid');
- if (id !== undefined) {
- if (Array.isArray (id)) {
- const length = id.length;
- id = (length > 1) ? id : id[0];
- }
- }
- const clientOrderId = this.safeString (params, 'userref');
- return {
- 'id': id,
- 'clientOrderId': clientOrderId,
- 'info': response,
- 'timestamp': undefined,
- 'datetime': undefined,
- 'lastTradeTimestamp': undefined,
- 'symbol': symbol,
- 'type': type,
- 'side': side,
- 'price': price,
- 'amount': amount,
- 'cost': undefined,
- 'average': undefined,
- 'filled': undefined,
- 'remaining': undefined,
- 'status': undefined,
- 'fee': undefined,
- 'trades': undefined,
- };
+ const response = await this.privatePostAddOrder (this.extend (request, query));
+ //
+ // {
+ // error: [],
+ // result: {
+ // descr: { order: 'buy 0.02100000 ETHUSDT @ limit 330.00' },
+ // txid: [ 'OEKVV2-IH52O-TPL6GZ' ]
+ // }
+ // }
+ //
+ const result = this.safeValue (response, 'result');
+ return this.parseOrder (result);
}
findMarketByAltnameOrId (id) {
@@ -68450,10 +79619,32 @@ module.exports = class kraken extends Exchange {
}
parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // descr: { order: 'buy 0.02100000 ETHUSDT @ limit 330.00' },
+ // txid: [ 'OEKVV2-IH52O-TPL6GZ' ]
+ // }
+ //
const description = this.safeValue (order, 'descr', {});
- const side = this.safeString (description, 'type');
- const type = this.safeString (description, 'ordertype');
- const marketId = this.safeString (description, 'pair');
+ const orderDescription = this.safeString (description, 'order');
+ let side = undefined;
+ let type = undefined;
+ let marketId = undefined;
+ let price = undefined;
+ let amount = undefined;
+ if (orderDescription !== undefined) {
+ const parts = orderDescription.split (' ');
+ side = this.safeString (parts, 0);
+ amount = this.safeFloat (parts, 1);
+ marketId = this.safeString (parts, 2);
+ type = this.safeString (parts, 4);
+ price = this.safeFloat (parts, 5);
+ }
+ side = this.safeString (description, 'type', side);
+ type = this.safeString (description, 'ordertype', type);
+ marketId = this.safeString (description, 'pair', marketId);
const foundMarket = this.findMarketByAltnameOrId (marketId);
let symbol = undefined;
if (foundMarket !== undefined) {
@@ -68463,16 +79654,19 @@ module.exports = class kraken extends Exchange {
market = this.getDelistedMarketById (marketId);
}
const timestamp = this.safeTimestamp (order, 'opentm');
- const amount = this.safeFloat (order, 'vol');
+ amount = this.safeFloat (order, 'vol', amount);
const filled = this.safeFloat (order, 'vol_exec');
- const remaining = amount - filled;
+ let remaining = undefined;
+ if ((amount !== undefined) && (filled !== undefined)) {
+ remaining = amount - filled;
+ }
let fee = undefined;
const cost = this.safeFloat (order, 'cost');
- let price = this.safeFloat (description, 'price');
- if ((price === undefined) || (price === 0)) {
+ price = this.safeFloat (description, 'price', price);
+ if ((price === undefined) || (price === 0.0)) {
price = this.safeFloat (description, 'price2');
}
- if ((price === undefined) || (price === 0)) {
+ if ((price === undefined) || (price === 0.0)) {
price = this.safeFloat (order, 'price', price);
}
const average = this.safeFloat (order, 'price');
@@ -68493,13 +79687,18 @@ module.exports = class kraken extends Exchange {
}
}
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- const id = this.safeString (order, 'id');
+ let id = this.safeString (order, 'id');
+ if (id === undefined) {
+ const txid = this.safeValue (order, 'txid');
+ id = this.safeString (txid, 0);
+ }
const clientOrderId = this.safeString (order, 'userref');
const rawTrades = this.safeValue (order, 'trades');
let trades = undefined;
if (rawTrades !== undefined) {
trades = this.parseTrades (rawTrades, market, undefined, undefined, { 'order': id });
}
+ const stopPrice = this.safeFloat (order, 'stopprice');
return {
'id': id,
'clientOrderId': clientOrderId,
@@ -68510,8 +79709,10 @@ module.exports = class kraken extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -68522,21 +79723,6 @@ module.exports = class kraken extends Exchange {
};
}
- parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
- const result = [];
- const ids = Object.keys (orders);
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- for (let i = 0; i < ids.length; i++) {
- const id = ids[i];
- const order = this.extend ({ 'id': id }, orders[id]);
- result.push (this.extend (this.parseOrder (order, market), params));
- }
- return this.filterBySymbolSinceLimit (result, symbol, since, limit);
- }
-
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const clientOrderId = this.safeValue2 (params, 'userref', 'clientOrderId');
@@ -68723,11 +79909,11 @@ module.exports = class kraken extends Exchange {
for (let i = 0; i < ids.length; i++) {
trades[ids[i]]['id'] = ids[i];
}
- const result = this.parseTrades (trades, undefined, since, limit);
- if (symbol === undefined) {
- return result;
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
}
- return this.filterBySymbol (result, symbol);
+ return this.parseTrades (trades, market, since, limit);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -68755,11 +79941,13 @@ module.exports = class kraken extends Exchange {
request['start'] = parseInt (since / 1000);
}
const response = await this.privatePostOpenOrders (this.extend (request, params));
- const orders = this.parseOrders (response['result']['open'], undefined, since, limit);
- if (symbol === undefined) {
- return orders;
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
}
- return this.filterBySymbol (orders, symbol);
+ const result = this.safeValue (response, 'result', {});
+ const orders = this.safeValue (result, 'open', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -68769,11 +79957,52 @@ module.exports = class kraken extends Exchange {
request['start'] = parseInt (since / 1000);
}
const response = await this.privatePostClosedOrders (this.extend (request, params));
- const orders = this.parseOrders (response['result']['closed'], undefined, since, limit);
- if (symbol === undefined) {
- return orders;
+ //
+ // {
+ // "error":[],
+ // "result":{
+ // "closed":{
+ // "OETZYO-UL524-QJMXCT":{
+ // "refid":null,
+ // "userref":null,
+ // "status":"canceled",
+ // "reason":"User requested",
+ // "opentm":1601489313.3898,
+ // "closetm":1601489346.5507,
+ // "starttm":0,
+ // "expiretm":0,
+ // "descr":{
+ // "pair":"ETHUSDT",
+ // "type":"buy",
+ // "ordertype":"limit",
+ // "price":"330.00",
+ // "price2":"0",
+ // "leverage":"none",
+ // "order":"buy 0.02100000 ETHUSDT @ limit 330.00",
+ // "close":""
+ // },
+ // "vol":"0.02100000",
+ // "vol_exec":"0.00000000",
+ // "cost":"0.00000",
+ // "fee":"0.00000",
+ // "price":"0.00000",
+ // "stopprice":"0.00000",
+ // "limitprice":"0.00000",
+ // "misc":"",
+ // "oflags":"fciq"
+ // },
+ // },
+ // "count":16
+ // }
+ // }
+ //
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
}
- return this.filterBySymbol (orders, symbol);
+ const result = this.safeValue (response, 'result', {});
+ const orders = this.safeValue (result, 'closed', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchDepositMethods (code, params = {}) {
@@ -68783,7 +80012,7 @@ module.exports = class kraken extends Exchange {
'asset': currency['id'],
};
const response = await this.privatePostDepositMethods (this.extend (request, params));
- return response['result'];
+ return this.safeValue (response, 'result');
}
parseTransactionStatus (status) {
@@ -68900,6 +80129,22 @@ module.exports = class kraken extends Exchange {
return this.parseTransactionsByType ('deposit', response['result'], code, since, limit);
}
+ async fetchTime (params = {}) {
+ // https://www.kraken.com/en-us/features/api#get-server-time
+ const response = await this.publicGetTime (params);
+ //
+ // {
+ // "error": [],
+ // "result": {
+ // "unixtime": 1591502873,
+ // "rfc1123": "Sun, 7 Jun 20 04:07:53 +0000"
+ // }
+ // }
+ //
+ const result = this.safeValue (response, 'result', {});
+ return this.safeTimestamp (result, 'unixtime');
+ }
+
async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
// https://www.kraken.com/en-us/help/api#withdraw-status
if (code === undefined) {
@@ -69015,7 +80260,7 @@ module.exports = class kraken extends Exchange {
const signature = this.hmac (binhash, secret, 'sha512', 'base64');
headers = {
'API-Key': this.apiKey,
- 'API-Sign': this.decode (signature),
+ 'API-Sign': signature,
'Content-Type': 'application/x-www-form-urlencoded',
};
} else {
@@ -69067,13 +80312,13 @@ module.exports = class kraken extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],101:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],100:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, AccountSuspended, InvalidNonce, NotSupported, BadRequest, AuthenticationError, BadSymbol, RateLimitExceeded } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, AccountSuspended, InvalidNonce, NotSupported, BadRequest, AuthenticationError, BadSymbol, RateLimitExceeded, PermissionDenied } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -69090,6 +80335,7 @@ module.exports = class kucoin extends Exchange {
'comment': 'Platform 2.0',
'has': {
'CORS': false,
+ 'fetchStatus': true,
'fetchTime': true,
'fetchMarkets': true,
'fetchCurrencies': true,
@@ -69115,7 +80361,7 @@ module.exports = class kucoin extends Exchange {
'fetchLedger': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/57369448-3cc3aa80-7196-11e9-883e-5ebeb35e4f57.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295558-132aaf80-c50e-11ea-9801-a2fb0c57c799.jpg',
'referral': 'https://www.kucoin.com/?rcode=E5wkqe',
'api': {
'public': 'https://openapi-v2.kucoin.com',
@@ -69193,7 +80439,7 @@ module.exports = class kucoin extends Exchange {
'margin/lend/trade/settled',
'margin/lend/assets',
'margin/market',
- 'margin/margin/trade/last',
+ 'margin/trade/last',
],
'post': [
'accounts',
@@ -69247,8 +80493,9 @@ module.exports = class kucoin extends Exchange {
'404': NotSupported,
'405': NotSupported,
'429': RateLimitExceeded,
- '500': ExchangeError,
+ '500': ExchangeNotAvailable, // Internal Server Error -- We had a problem with our server. Try again later.
'503': ExchangeNotAvailable,
+ '101030': PermissionDenied, // {"code":"101030","msg":"You haven't yet enabled the margin trading"}
'200004': InsufficientFunds,
'230003': InsufficientFunds, // {"code":"230003","msg":"Balance insufficient!"}
'260100': InsufficientFunds, // {"code":"260100","msg":"account.noBalance"}
@@ -69269,6 +80516,7 @@ module.exports = class kucoin extends Exchange {
},
'broad': {
'Exceeded the access frequency': RateLimitExceeded,
+ 'require more permission': PermissionDenied,
},
},
'fees': {
@@ -69302,6 +80550,7 @@ module.exports = class kucoin extends Exchange {
'versions': {
'public': {
'GET': {
+ 'status': 'v1',
'market/orderbook/level{level}': 'v1',
'market/orderbook/level2': 'v2',
'market/orderbook/level2_20': 'v1',
@@ -69323,8 +80572,8 @@ module.exports = class kucoin extends Exchange {
return this.milliseconds ();
}
- async loadTimeDifference () {
- const response = await this.publicGetTimestamp ();
+ async loadTimeDifference (params = {}) {
+ const response = await this.publicGetTimestamp (params);
const after = this.milliseconds ();
const kucoinTime = this.safeInteger (response, 'data');
this.options['timeDifference'] = parseInt (after - kucoinTime);
@@ -69343,6 +80592,29 @@ module.exports = class kucoin extends Exchange {
return this.safeInteger (response, 'data');
}
+ async fetchStatus (params = {}) {
+ const response = await this.publicGetStatus (params);
+ //
+ // {
+ // "code":"200000",
+ // "data":{
+ // "msg":"",
+ // "status":"open"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ let status = this.safeValue (data, 'status');
+ if (status !== undefined) {
+ status = (status === 'open') ? 'ok' : 'maintenance';
+ this.status = this.extend (this.status, {
+ 'status': status,
+ 'updated': this.milliseconds (),
+ });
+ }
+ return this.status;
+ }
+
async fetchMarkets (params = {}) {
const response = await this.publicGetSymbols (params);
//
@@ -69414,10 +80686,17 @@ module.exports = class kucoin extends Exchange {
const response = await this.publicGetCurrencies (params);
//
// {
- // precision: 10,
- // name: 'KCS',
- // fullName: 'KCS shares',
- // currency: 'KCS'
+ // "currency": "OMG",
+ // "name": "OMG",
+ // "fullName": "OmiseGO",
+ // "precision": 8,
+ // "confirms": 12,
+ // "withdrawalMinSize": "4",
+ // "withdrawalMinFee": "1.25",
+ // "isWithdrawEnabled": false,
+ // "isDepositEnabled": false,
+ // "isMarginEnabled": false,
+ // "isDebitEnabled": false
// }
//
const responseData = response['data'];
@@ -69428,14 +80707,18 @@ module.exports = class kucoin extends Exchange {
const name = this.safeString (entry, 'fullName');
const code = this.safeCurrencyCode (id);
const precision = this.safeInteger (entry, 'precision');
+ const isWithdrawEnabled = this.safeValue (entry, 'isWithdrawEnabled', false);
+ const isDepositEnabled = this.safeValue (entry, 'isDepositEnabled', false);
+ const fee = this.safeFloat (entry, 'withdrawalMinFee');
+ const active = (isWithdrawEnabled && isDepositEnabled);
result[code] = {
'id': id,
'name': name,
'code': code,
'precision': precision,
'info': entry,
- 'active': undefined,
- 'fee': undefined,
+ 'active': active,
+ 'fee': fee,
'limits': this.limits,
};
}
@@ -69545,24 +80828,11 @@ module.exports = class kucoin extends Exchange {
percentage = percentage * 100;
}
const last = this.safeFloat2 (ticker, 'last', 'lastTradedPrice');
- let symbol = undefined;
const marketId = this.safeString (ticker, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const baseVolume = this.safeFloat (ticker, 'vol');
+ const quoteVolume = this.safeFloat (ticker, 'volValue');
+ const vwap = this.vwap (baseVolume, quoteVolume);
const timestamp = this.safeInteger2 (ticker, 'time', 'datetime');
return {
'symbol': symbol,
@@ -69574,7 +80844,7 @@ module.exports = class kucoin extends Exchange {
'bidVolume': undefined,
'ask': this.safeFloat (ticker, 'sell'),
'askVolume': undefined,
- 'vwap': undefined,
+ 'vwap': vwap,
'open': this.safeFloat (ticker, 'open'),
'close': last,
'last': last,
@@ -69582,8 +80852,8 @@ module.exports = class kucoin extends Exchange {
'change': this.safeFloat (ticker, 'changePrice'),
'percentage': percentage,
'average': this.safeFloat (ticker, 'averagePrice'),
- 'baseVolume': this.safeFloat (ticker, 'vol'),
- 'quoteVolume': this.safeFloat (ticker, 'volValue'),
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
'info': ticker,
};
}
@@ -69621,7 +80891,7 @@ module.exports = class kucoin extends Exchange {
result[symbol] = ticker;
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -69651,7 +80921,7 @@ module.exports = class kucoin extends Exchange {
return this.parseTicker (response['data'], market);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// [
// "1545904980", // Start time of the candle cycle
@@ -69664,12 +80934,12 @@ module.exports = class kucoin extends Exchange {
// ]
//
return [
- parseInt (ohlcv[0]) * 1000,
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[5]),
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -69699,8 +80969,18 @@ module.exports = class kucoin extends Exchange {
}
request['endAt'] = parseInt (Math.floor (endAt / 1000));
const response = await this.publicGetMarketCandles (this.extend (request, params));
- const responseData = this.safeValue (response, 'data', []);
- return this.parseOHLCVs (responseData, market, timeframe, since, limit);
+ //
+ // {
+ // "code":"200000",
+ // "data":[
+ // ["1591517700","0.025078","0.025069","0.025084","0.025064","18.9883256","0.4761861079404"],
+ // ["1591516800","0.025089","0.025079","0.025089","0.02506","99.4716622","2.494143499081"],
+ // ["1591515900","0.025079","0.02509","0.025091","0.025068","59.83701271","1.50060885172798"],
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async createDepositAddress (code, params = {}) {
@@ -69756,7 +81036,7 @@ module.exports = class kucoin extends Exchange {
async fetchOrderBook (symbol, limit = undefined, params = {}) {
const level = this.safeInteger (params, 'level', 2);
let levelLimit = level.toString ();
- if (level === '2') {
+ if (levelLimit === '2') {
if (limit !== undefined) {
if ((limit !== 20) && (limit !== 100)) {
throw new ExchangeError (this.id + ' fetchOrderBook limit argument must be undefined, 20 or 100');
@@ -69823,9 +81103,10 @@ module.exports = class kucoin extends Exchange {
await this.loadMarkets ();
const marketId = this.marketId (symbol);
// required param, cannot be used twice
- const clientOid = this.uuid ();
+ const clientOrderId = this.safeString2 (params, 'clientOid', 'clientOrderId', this.uuid ());
+ params = this.omit (params, [ 'clientOid', 'clientOrderId' ]);
const request = {
- 'clientOid': clientOid,
+ 'clientOid': clientOrderId,
'side': side,
'symbol': marketId,
'type': type,
@@ -69852,21 +81133,26 @@ module.exports = class kucoin extends Exchange {
//
const data = this.safeValue (response, 'data', {});
const timestamp = this.milliseconds ();
+ const id = this.safeString (data, 'orderId');
const order = {
- 'id': this.safeString (data, 'orderId'),
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'info': data,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
'side': side,
'price': price,
+ 'amount': undefined,
'cost': undefined,
+ 'average': undefined,
'filled': undefined,
'remaining': undefined,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
+ 'status': undefined,
'fee': undefined,
- 'status': 'open',
- 'clientOrderId': clientOid,
- 'info': data,
+ 'trades': undefined,
};
if (!this.safeValue (params, 'quoteAmount')) {
order['amount'] = amount;
@@ -69955,6 +81241,12 @@ module.exports = class kucoin extends Exchange {
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
+ // a special case for undefined ids
+ // otherwise a wrong endpoint for all orders will be triggered
+ // https://github.com/ccxt/ccxt/issues/7234
+ if (id === undefined) {
+ throw new InvalidOrder (this.id + ' fetchOrder requires an order id');
+ }
const request = {
'orderId': id,
};
@@ -69963,7 +81255,7 @@ module.exports = class kucoin extends Exchange {
market = this.market (symbol);
}
const response = await this.privateGetOrdersOrderId (this.extend (request, params));
- const responseData = response['data'];
+ const responseData = this.safeValue (response, 'data');
return this.parseOrder (responseData, market);
}
@@ -70003,25 +81295,8 @@ module.exports = class kucoin extends Exchange {
// "createdAt": 1547026471000 // time
// }
//
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- market = this.safeValue (this.markets_by_id, marketId);
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const orderId = this.safeString (order, 'id');
const type = this.safeString (order, 'type');
const timestamp = this.safeInteger (order, 'createdAt');
@@ -70036,8 +81311,10 @@ module.exports = class kucoin extends Exchange {
const cost = this.safeFloat (order, 'dealFunds');
const remaining = amount - filled;
// bool
- let status = order['isActive'] ? 'open' : 'closed';
- status = order['cancelExist'] ? 'canceled' : status;
+ const isActive = this.safeValue (order, 'isActive', false);
+ const cancelExist = this.safeValue (order, 'cancelExist', false);
+ let status = isActive ? 'open' : 'closed';
+ status = cancelExist ? 'canceled' : status;
const fee = {
'currency': feeCurrency,
'cost': feeCost,
@@ -70052,14 +81329,18 @@ module.exports = class kucoin extends Exchange {
}
}
const clientOrderId = this.safeString (order, 'clientOid');
+ const timeInForce = this.safeString (order, 'timeInForce');
+ const stopPrice = this.safeFloat (order, 'stopPrice');
return {
'id': orderId,
'clientOrderId': clientOrderId,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'amount': amount,
'price': price,
+ 'stopPrice': stopPrice,
'cost': cost,
'filled': filled,
'remaining': remaining,
@@ -70267,24 +81548,8 @@ module.exports = class kucoin extends Exchange {
// "id":"5c4d389e4c8c60413f78e2e5",
// }
//
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const id = this.safeString2 (trade, 'tradeId', 'id');
const orderId = this.safeString (trade, 'orderId');
const takerOrMaker = this.safeString (trade, 'liquidity');
@@ -70317,7 +81582,10 @@ module.exports = class kucoin extends Exchange {
'rate': this.safeFloat (trade, 'feeRate'),
};
}
- const type = this.safeString (trade, 'type');
+ let type = this.safeString (trade, 'type');
+ if (type === 'match') {
+ type = undefined;
+ }
let cost = this.safeFloat2 (trade, 'funds', 'dealValue');
if (cost === undefined) {
if (amount !== undefined) {
@@ -70825,7 +82093,16 @@ module.exports = class kucoin extends Exchange {
}, headers);
const payload = timestamp + method + endpoint + endpart;
const signature = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'base64');
- headers['KC-API-SIGN'] = this.decode (signature);
+ headers['KC-API-SIGN'] = signature;
+ const partner = this.safeValue (this.options, 'partner', {});
+ const partnerId = this.safeString (partner, 'id');
+ const partnerSecret = this.safeString (partner, 'secret');
+ if ((partnerId !== undefined) && (partnerSecret !== undefined)) {
+ const partnerPayload = timestamp + partnerId + this.apiKey;
+ const partnerSignature = this.hmac (this.encode (partnerPayload), this.encode (partnerSecret), 'sha256', 'base64');
+ headers['KC-API-PARTNER-SIGN'] = partnerSignature;
+ headers['KC-API-PARTNER'] = partnerId;
+ }
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
@@ -70848,7 +82125,7 @@ module.exports = class kucoin extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],102:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],101:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -70877,7 +82154,7 @@ module.exports = class kuna extends acx {
'timeframes': undefined,
'urls': {
'referral': 'https://kuna.io?r=kunaid-gvfihe8az7o4',
- 'logo': 'https://user-images.githubusercontent.com/1294454/31697638-912824fa-b3c1-11e7-8c36-cf9606eb94ac.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87153927-f0578b80-c2c0-11ea-84b6-74612568e9e1.jpg',
'api': 'https://kuna.io',
'www': 'https://kuna.io',
'doc': 'https://kuna.io/documents/api',
@@ -70911,7 +82188,7 @@ module.exports = class kuna extends acx {
}
async fetchMarkets (params = {}) {
- const quotes = [ 'btc', 'eth', 'eurs', 'rub', 'uah', 'usd', 'usdt' ];
+ const quotes = [ 'btc', 'eth', 'eurs', 'rub', 'uah', 'usd', 'usdt', 'gol' ];
const pricePrecisions = {
'UAH': 0,
};
@@ -70997,7 +82274,7 @@ module.exports = class kuna extends acx {
'ask': 'sell',
'bid': 'buy',
};
- side = this.safeString (sideMap, side);
+ side = this.safeString (sideMap, side, side);
}
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'volume');
@@ -71044,10 +82321,10 @@ module.exports = class kuna extends acx {
return this.parseTrades (response, market, since, limit);
}
- async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limits = undefined, params = {}) {
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
- const trades = await this.fetchTrades (symbol, since, limits, params);
- const ohlcvc = this.buildOHLCVC (trades, timeframe, since, limits);
+ const trades = await this.fetchTrades (symbol, since, limit, params);
+ const ohlcvc = this.buildOHLCVC (trades, timeframe, since, limit);
const result = [];
for (let i = 0; i < ohlcvc.length; i++) {
const ohlcv = ohlcvc[i];
@@ -71064,7 +82341,7 @@ module.exports = class kuna extends acx {
}
};
-},{"./acx.js":4,"./base/errors":9}],103:[function(require,module,exports){
+},{"./acx.js":3,"./base/errors":7}],102:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -71083,9 +82360,16 @@ module.exports = class lakebtc extends Exchange {
'version': 'api_v2',
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': true,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/28074120-72b7c38a-6660-11e7-92d9-d9027502281d.jpg',
@@ -71224,16 +82508,13 @@ module.exports = class lakebtc extends Exchange {
const ids = Object.keys (response);
const result = {};
for (let i = 0; i < ids.length; i++) {
- let symbol = ids[i];
- const ticker = response[symbol];
- let market = undefined;
- if (symbol in this.markets_by_id) {
- market = this.markets_by_id[symbol];
- symbol = market['symbol'];
- }
+ const marketId = ids[i];
+ const ticker = response[marketId];
+ const market = this.safeMarket (marketId);
+ const symbol = market['symbol'];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -71361,7 +82642,7 @@ module.exports = class lakebtc extends Exchange {
];
query = query.join ('&');
const signature = this.hmac (this.encode (query), this.encode (this.secret), 'sha1');
- const auth = this.encode (this.apiKey + ':' + signature);
+ const auth = this.apiKey + ':' + signature;
const signature64 = this.decode (this.stringToBase64 (auth));
headers = {
'Json-Rpc-Tonce': nonceAsString,
@@ -71390,7 +82671,7 @@ module.exports = class lakebtc extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],104:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],103:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -71743,14 +83024,8 @@ module.exports = class latoken extends Exchange {
// "priceChange":-0.1500
// }
//
- let symbol = undefined;
const marketId = this.safeString (ticker, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const open = this.safeFloat (ticker, 'open');
const close = this.safeFloat (ticker, 'close');
let change = undefined;
@@ -71826,11 +83101,9 @@ module.exports = class latoken extends Exchange {
for (let i = 0; i < response.length; i++) {
const ticker = this.parseTicker (response[i]);
const symbol = ticker['symbol'];
- if (symbols === undefined || this.inArray (symbol, symbols)) {
- result[symbol] = ticker;
- }
+ result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
parseTrade (trade, market = undefined) {
@@ -72011,13 +83284,7 @@ module.exports = class latoken extends Exchange {
const id = this.safeString (order, 'orderId');
const timestamp = this.safeTimestamp (order, 'timeCreated');
const marketId = this.safeString (order, 'symbol');
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const side = this.safeString (order, 'side');
const type = this.safeString (order, 'orderType');
const price = this.safeFloat (order, 'price');
@@ -72052,8 +83319,10 @@ module.exports = class latoken extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -72291,7 +83560,7 @@ module.exports = class latoken extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],105:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],104:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -72309,12 +83578,20 @@ module.exports = class lbank extends Exchange {
'countries': [ 'CN' ],
'version': 'v1',
'has': {
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': false, // status 0 API doesn't work
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchMarkets': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': false, // status 0 API doesn't work
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': 'minute1',
@@ -72397,6 +83674,7 @@ module.exports = class lbank extends Exchange {
},
'commonCurrencies': {
'VET_ERC20': 'VEN',
+ 'PNT': 'Penta',
},
'options': {
'cacheSecretAsPem': true,
@@ -72550,7 +83828,7 @@ module.exports = class lbank extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = 60, params = {}) {
@@ -72618,14 +83896,24 @@ module.exports = class lbank extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1590969600,
+ // 0.02451657,
+ // 0.02452675,
+ // 0.02443701,
+ // 0.02447814,
+ // 238.38210000
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- ohlcv[1],
- ohlcv[2],
- ohlcv[3],
- ohlcv[4],
- ohlcv[5],
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -72645,6 +83933,13 @@ module.exports = class lbank extends Exchange {
'time': parseInt (since / 1000),
};
const response = await this.publicGetKline (this.extend (request, params));
+ //
+ // [
+ // [1590969600,0.02451657,0.02452675,0.02443701,0.02447814,238.38210000],
+ // [1590969660,0.02447814,0.02449883,0.02443209,0.02445973,212.40270000],
+ // [1590969720,0.02445973,0.02452067,0.02445909,0.02446151,266.16920000],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -72753,8 +84048,10 @@ module.exports = class lbank extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -72786,10 +84083,7 @@ module.exports = class lbank extends Exchange {
order['order_type'] = type;
order['create_time'] = this.milliseconds ();
order['info'] = response;
- order = this.parseOrder (order, market);
- const id = order['id'];
- this.orders[id] = order;
- return order;
+ return this.parseOrder (order, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -72812,7 +84106,8 @@ module.exports = class lbank extends Exchange {
'order_id': id,
};
const response = await this.privatePostOrdersInfo (this.extend (request, params));
- const orders = this.parseOrders (response['orders'], market);
+ const data = this.safeValue (response, 'orders', []);
+ const orders = this.parseOrders (data, market);
const numOrders = orders.length;
if (numOrders === 1) {
return orders[0];
@@ -72833,7 +84128,8 @@ module.exports = class lbank extends Exchange {
'page_length': limit,
};
const response = await this.privatePostOrdersInfoHistory (this.extend (request, params));
- return this.parseOrders (response['orders'], undefined, since, limit);
+ const data = this.safeValue (response, 'orders', []);
+ return this.parseOrders (data, undefined, since, limit);
}
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -72859,7 +84155,7 @@ module.exports = class lbank extends Exchange {
}
const response = this.privatePostWithdraw (this.extend (request, params));
return {
- 'id': response['id'],
+ 'id': this.safeString (response, 'id'),
'info': response,
};
}
@@ -72964,12 +84260,13 @@ module.exports = class lbank extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],106:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],105:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
+const { TICK_SIZE } = require ('./base/functions/number');
const { ExchangeError, ArgumentsRequired, InvalidNonce, OrderNotFound, InvalidOrder, InsufficientFunds, AuthenticationError, DDoSProtection, NotSupported } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -72983,14 +84280,22 @@ module.exports = class liquid extends Exchange {
'version': '2',
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchCurrencies': true,
- 'fetchTickers': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'urls': {
@@ -73001,7 +84306,7 @@ module.exports = class liquid extends Exchange {
'https://developers.liquid.com',
],
'fees': 'https://help.liquid.com/getting-started-with-liquid/the-platform/fee-structure',
- 'referral': 'https://www.liquid.com?affiliate=SbzC62lt30976',
+ 'referral': 'https://www.liquid.com/sign-up/?affiliate=SbzC62lt30976',
},
'api': {
'public': {
@@ -73017,6 +84322,7 @@ module.exports = class liquid extends Exchange {
},
'private': {
'get': [
+ 'accounts', // undocumented https://github.com/ccxt/ccxt/pull/7493
'accounts/balance',
'accounts/main_asset',
'accounts/{id}',
@@ -73061,6 +84367,77 @@ module.exports = class liquid extends Exchange {
],
},
},
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.0015,
+ 'maker': 0.0000,
+ 'tiers': {
+ 'perpetual': {
+ 'maker': [
+ [ 0, 0.0000 ],
+ [ 25000, 0.0000 ],
+ [ 50000, -0.00025 ],
+ [ 100000, -0.00025 ],
+ [ 1000000, -0.00025 ],
+ [ 10000000, -0.00025 ],
+ [ 25000000, -0.00025 ],
+ [ 50000000, -0.00025 ],
+ [ 75000000, -0.00025 ],
+ [ 100000000, -0.00025 ],
+ [ 200000000, -0.00025 ],
+ [ 300000000, -0.00025 ],
+ ],
+ 'taker': [
+ [ 0, 0.000600 ],
+ [ 25000, 0.000575 ],
+ [ 50000, 0.000550 ],
+ [ 100000, 0.000525 ],
+ [ 1000000, 0.000500 ],
+ [ 10000000, 0.000475 ],
+ [ 25000000, 0.000450 ],
+ [ 50000000, 0.000425 ],
+ [ 75000000, 0.000400 ],
+ [ 100000000, 0.000375 ],
+ [ 200000000, 0.000350 ],
+ [ 300000000, 0.000325 ],
+ ],
+ },
+ 'spot': {
+ 'taker': [
+ [ 0, 0.0015 ],
+ [ 10000, 0.0015 ],
+ [ 20000, 0.0014 ],
+ [ 50000, 0.0013 ],
+ [ 100000, 0.0010 ],
+ [ 1000000, 0.0008 ],
+ [ 5000000, 0.0006 ],
+ [ 10000000, 0.0005 ],
+ [ 25000000, 0.0005 ],
+ [ 50000000, 0.00045 ],
+ [ 100000000, 0.0004 ],
+ [ 200000000, 0.0003 ],
+ ],
+ 'maker': [
+ [ 0, 0.0000 ],
+ [ 10000, 0.0015 ],
+ [ 20000, 0.1400 ],
+ [ 50000, 0.1300 ],
+ [ 100000, 0.0800 ],
+ [ 1000000, 0.0004 ],
+ [ 5000000, 0.00035 ],
+ [ 10000000, 0.00025 ],
+ [ 25000000, 0.0000 ],
+ [ 50000000, 0.0000 ],
+ [ 100000000, 0.0000 ],
+ [ 200000000, 0.0000 ],
+ ],
+ },
+ },
+ },
+ },
+ 'precisionMode': TICK_SIZE,
'exceptions': {
'API rate limit exceeded. Please retry after 300s': DDoSProtection,
'API Authentication failed': AuthenticationError,
@@ -73071,10 +84448,12 @@ module.exports = class liquid extends Exchange {
'not_enough_free_balance': InsufficientFunds,
'must_be_positive': InvalidOrder,
'less_than_order_size': InvalidOrder,
+ 'price_too_high': InvalidOrder,
},
'commonCurrencies': {
'WIN': 'WCOIN',
'HOT': 'HOT Token',
+ 'MIOTA': 'IOTA', // https://github.com/ccxt/ccxt/issues/7487
},
'options': {
'cancelOrderException': true,
@@ -73112,6 +84491,7 @@ module.exports = class liquid extends Exchange {
const amountPrecision = this.safeInteger (currency, 'display_precision');
const pricePrecision = this.safeInteger (currency, 'quoting_precision');
const precision = Math.max (amountPrecision, pricePrecision);
+ const decimalPrecision = 1 / Math.pow (10, precision);
result[code] = {
'id': id,
'code': code,
@@ -73119,7 +84499,7 @@ module.exports = class liquid extends Exchange {
'name': code,
'active': active,
'fee': this.safeFloat (currency, 'withdrawal_fee'),
- 'precision': precision,
+ 'precision': decimalPrecision,
'limits': {
'amount': {
'min': Math.pow (10, -amountPrecision),
@@ -73148,30 +84528,40 @@ module.exports = class liquid extends Exchange {
//
// [
// {
- // id: '7',
- // product_type: 'CurrencyPair',
- // code: 'CASH',
- // name: ' CASH Trading',
- // market_ask: 8865.79147,
- // market_bid: 8853.95988,
- // indicator: 1,
- // currency: 'SGD',
- // currency_pair_code: 'BTCSGD',
- // symbol: 'S$',
- // btc_minimum_withdraw: null,
- // fiat_minimum_withdraw: null,
- // pusher_channel: 'product_cash_btcsgd_7',
- // taker_fee: 0,
- // maker_fee: 0,
- // low_market_bid: '8803.25579',
- // high_market_ask: '8905.0',
- // volume_24h: '15.85443468',
- // last_price_24h: '8807.54625',
- // last_traded_price: '8857.77206',
- // last_traded_quantity: '0.00590974',
- // quoted_currency: 'SGD',
- // base_currency: 'BTC',
- // disabled: false,
+ // "id":"637",
+ // "product_type":"CurrencyPair",
+ // "code":"CASH",
+ // "name":null,
+ // "market_ask":"0.00000797",
+ // "market_bid":"0.00000727",
+ // "indicator":null,
+ // "currency":"BTC",
+ // "currency_pair_code":"TFTBTC",
+ // "symbol":null,
+ // "btc_minimum_withdraw":null,
+ // "fiat_minimum_withdraw":null,
+ // "pusher_channel":"product_cash_tftbtc_637",
+ // "taker_fee":"0.0",
+ // "maker_fee":"0.0",
+ // "low_market_bid":"0.00000685",
+ // "high_market_ask":"0.00000885",
+ // "volume_24h":"3696.0755956",
+ // "last_price_24h":"0.00000716",
+ // "last_traded_price":"0.00000766",
+ // "last_traded_quantity":"1748.0377978",
+ // "average_price":null,
+ // "quoted_currency":"BTC",
+ // "base_currency":"TFT",
+ // "tick_size":"0.00000001",
+ // "disabled":false,
+ // "margin_enabled":false,
+ // "cfd_enabled":false,
+ // "perpetual_enabled":false,
+ // "last_event_timestamp":"1596962820.000797146",
+ // "timestamp":"1596962820.000797146",
+ // "multiplier_up":"9.0",
+ // "multiplier_down":"0.1",
+ // "average_time_interval":null
// },
// ]
//
@@ -73179,32 +84569,44 @@ module.exports = class liquid extends Exchange {
//
// [
// {
- // "id": "603",
- // "product_type": "Perpetual",
- // "code": "CASH",
- // "name": null,
- // "market_ask": "1143900",
- // "market_bid": "1143250",
- // "currency": "JPY",
- // "currency_pair_code": "P-BTCJPY",
- // "pusher_channel": "product_cash_p-btcjpy_603",
- // "taker_fee": "0.0",
- // "maker_fee": "0.0",
- // "low_market_bid": "1124450.0",
- // "high_market_ask": "1151750.0",
- // "volume_24h": "0.1756",
- // "last_price_24h": "1129850.0",
- // "last_traded_price": "1144700.0",
- // "last_traded_quantity": "0.014",
- // "quoted_currency": "JPY",
- // "base_currency": "P-BTC",
- // "tick_size": "50.0",
- // "perpetual_enabled": true,
- // "index_price": "1142636.03935",
- // "mark_price": "1143522.18417",
- // "funding_rate": "0.00033",
- // "fair_price": "1143609.31009",
- // "timestamp": "1581558659.195353100",
+ // "id":"604",
+ // "product_type":"Perpetual",
+ // "code":"CASH",
+ // "name":null,
+ // "market_ask":"11721.5",
+ // "market_bid":"11719.0",
+ // "indicator":null,
+ // "currency":"USD",
+ // "currency_pair_code":"P-BTCUSD",
+ // "symbol":"$",
+ // "btc_minimum_withdraw":null,
+ // "fiat_minimum_withdraw":null,
+ // "pusher_channel":"product_cash_p-btcusd_604",
+ // "taker_fee":"0.0012",
+ // "maker_fee":"0.0",
+ // "low_market_bid":"11624.5",
+ // "high_market_ask":"11859.0",
+ // "volume_24h":"0.271",
+ // "last_price_24h":"11621.5",
+ // "last_traded_price":"11771.5",
+ // "last_traded_quantity":"0.09",
+ // "average_price":"11771.5",
+ // "quoted_currency":"USD",
+ // "base_currency":"P-BTC",
+ // "tick_size":"0.5",
+ // "disabled":false,
+ // "margin_enabled":false,
+ // "cfd_enabled":false,
+ // "perpetual_enabled":true,
+ // "last_event_timestamp":"1596963309.418853092",
+ // "timestamp":"1596963309.418853092",
+ // "multiplier_up":null,
+ // "multiplier_down":"0.1",
+ // "average_time_interval":300,
+ // "index_price":"11682.8124",
+ // "mark_price":"11719.96781",
+ // "funding_rate":"0.00273",
+ // "fair_price":"11720.2745"
// },
// ]
//
@@ -73234,31 +84636,22 @@ module.exports = class liquid extends Exchange {
} else {
symbol = base + '/' + quote;
}
- const maker = this.safeFloat (market, 'maker_fee');
- const taker = this.safeFloat (market, 'taker_fee');
+ let maker = this.fees['trading']['maker'];
+ let taker = this.fees['trading']['taker'];
+ if (type === 'swap') {
+ maker = this.safeFloat (market, 'maker_fee', this.fees['trading']['maker']);
+ taker = this.safeFloat (market, 'taker_fee', this.fees['trading']['taker']);
+ }
const disabled = this.safeValue (market, 'disabled', false);
const active = !disabled;
const baseCurrency = this.safeValue (currenciesByCode, base);
- const quoteCurrency = this.safeValue (currenciesByCode, quote);
const precision = {
- 'amount': 8,
- 'price': 8,
+ 'amount': 0.00000001,
+ 'price': this.safeFloat (market, 'tick_size'),
};
let minAmount = undefined;
if (baseCurrency !== undefined) {
minAmount = this.safeFloat (baseCurrency['info'], 'minimum_order_quantity');
- // precision['amount'] = this.safeInteger (baseCurrency['info'], 'quoting_precision');
- }
- let minPrice = undefined;
- if (quoteCurrency !== undefined) {
- precision['price'] = this.safeInteger (quoteCurrency['info'], 'quoting_precision');
- minPrice = Math.pow (10, -precision['price']);
- }
- let minCost = undefined;
- if (minPrice !== undefined) {
- if (minAmount !== undefined) {
- minCost = minPrice * minAmount;
- }
}
const limits = {
'amount': {
@@ -73266,11 +84659,11 @@ module.exports = class liquid extends Exchange {
'max': undefined,
},
'price': {
- 'min': minPrice,
+ 'min': undefined,
'max': undefined,
},
'cost': {
- 'min': minCost,
+ 'min': undefined,
'max': undefined,
},
};
@@ -73297,21 +84690,60 @@ module.exports = class liquid extends Exchange {
async fetchBalance (params = {}) {
await this.loadMarkets ();
- const response = await this.privateGetAccountsBalance (params);
+ const response = await this.privateGetAccounts (params);
//
- // [
- // {"currency":"USD","balance":"0.0"},
- // {"currency":"BTC","balance":"0.0"},
- // {"currency":"ETH","balance":"0.1651354"}
- // ]
+ // {
+ // crypto_accounts: [
+ // {
+ // id: 2221179,
+ // currency: 'USDT',
+ // balance: '0.0',
+ // reserved_balance: '0.0',
+ // pusher_channel: 'user_xxxxx_account_usdt',
+ // lowest_offer_interest_rate: null,
+ // highest_offer_interest_rate: null,
+ // address: '0',
+ // currency_symbol: 'USDT',
+ // minimum_withdraw: null,
+ // currency_type: 'crypto'
+ // },
+ // ],
+ // fiat_accounts: [
+ // {
+ // id: 1112734,
+ // currency: 'USD',
+ // balance: '0.0',
+ // reserved_balance: '0.0',
+ // pusher_channel: 'user_xxxxx_account_usd',
+ // lowest_offer_interest_rate: null,
+ // highest_offer_interest_rate: null,
+ // currency_symbol: '$',
+ // send_to_btc_address: null,
+ // exchange_rate: '1.0',
+ // currency_type: 'fiat'
+ // }
+ // ]
+ // }
//
const result = { 'info': response };
- for (let i = 0; i < response.length; i++) {
- const balance = response[i];
+ const crypto = this.safeValue (response, 'crypto_accounts', []);
+ const fiat = this.safeValue (response, 'fiat_accounts', []);
+ for (let i = 0; i < crypto.length; i++) {
+ const balance = crypto[i];
const currencyId = this.safeString (balance, 'currency');
const code = this.safeCurrencyCode (currencyId);
const account = this.account ();
account['total'] = this.safeFloat (balance, 'balance');
+ account['used'] = this.safeFloat (balance, 'reserved_balance');
+ result[code] = account;
+ }
+ for (let i = 0; i < fiat.length; i++) {
+ const balance = fiat[i];
+ const currencyId = this.safeString (balance, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['total'] = this.safeFloat (balance, 'balance');
+ account['used'] = this.safeFloat (balance, 'reserved_balance');
result[code] = account;
}
return this.parseBalance (result);
@@ -73399,7 +84831,7 @@ module.exports = class liquid extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -73495,13 +84927,18 @@ module.exports = class liquid extends Exchange {
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_order_id');
+ params = this.omit (params, [ 'clientOrderId', 'client_order_id' ]);
const request = {
'order_type': type,
'product_id': this.marketId (symbol),
'side': side,
'quantity': this.amountToPrecision (symbol, amount),
};
- if (type === 'limit') {
+ if (clientOrderId !== undefined) {
+ request['client_order_id'] = clientOrderId;
+ }
+ if ((type === 'limit') || (type === 'limit_post_only') || (type === 'market_with_range') || (type === 'stop')) {
request['price'] = this.priceToPrecision (symbol, price);
}
const response = await this.privatePostOrders (this.extend (request, params));
@@ -73524,7 +84961,8 @@ module.exports = class liquid extends Exchange {
// "product_code": "CASH",
// "funding_currency": "USD",
// "currency_pair_code": "BTCUSD",
- // "order_fee": "0.0"
+ // "order_fee": "0.0",
+ // "client_order_id": null,
// }
//
return this.parseOrder (response);
@@ -73593,6 +85031,7 @@ module.exports = class liquid extends Exchange {
// "funding_currency": "USD",
// "currency_pair_code": "BTCUSD",
// "order_fee": "0.0"
+ // "client_order_id": null,
// }
//
// fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders
@@ -73679,17 +85118,20 @@ module.exports = class liquid extends Exchange {
remaining = amount - filled;
}
const side = this.safeString (order, 'side');
+ const clientOrderId = this.safeString (order, 'client_order_id');
return {
'id': orderId,
- 'clientOrderId': undefined,
+ 'clientOrderId': clientOrderId,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
'type': type,
+ 'timeInForce': undefined,
'status': status,
'symbol': symbol,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': filled,
'cost': cost,
@@ -73894,10 +85336,12 @@ module.exports = class liquid extends Exchange {
const nonce = this.nonce ();
const request = {
'path': url,
- 'nonce': nonce,
'token_id': this.apiKey,
'iat': Math.floor (nonce / 1000), // issued at
};
+ if (!('client_order_id' in query)) {
+ request['nonce'] = nonce;
+ }
headers['X-Quoine-Auth'] = this.jwt (request, this.encode (this.secret));
} else {
if (Object.keys (query).length) {
@@ -73952,13 +85396,13 @@ module.exports = class liquid extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],107:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],106:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, AuthenticationError, NotSupported, InvalidOrder, OrderNotFound, ExchangeNotAvailable, RateLimitExceeded, InsufficientFunds } = require ('./base/errors');
+const { ExchangeError, OnMaintenance, BadResponse, ArgumentsRequired, AuthenticationError, NotSupported, InvalidOrder, OrderNotFound, ExchangeNotAvailable, RateLimitExceeded, InsufficientFunds } = require ('./base/errors');
const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -73972,18 +85416,25 @@ module.exports = class livecoin extends Exchange {
'rateLimit': 1000,
'userAgent': this.userAgents['chrome'],
'has': {
+ 'cancelOrder': true,
+ 'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
- 'CORS': false,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
'fetchTickers': true,
- 'fetchCurrencies': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
- 'fetchOrders': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'fetchMyTrades': true,
'fetchWithdrawals': true,
'withdraw': true,
},
@@ -74046,19 +85497,23 @@ module.exports = class livecoin extends Exchange {
},
},
'commonCurrencies': {
+ 'BIT': 'First Bitcoin',
'BTCH': 'Bithash',
'CPC': 'Capricoin',
+ 'CBC': 'CryptoBossCoin', // conflict with CBC (CashBet Coin)
'CPT': 'Cryptos', // conflict with CPT = Contents Protocol https://github.com/ccxt/ccxt/issues/4920 and https://github.com/ccxt/ccxt/issues/6081
'EDR': 'E-Dinar Coin', // conflicts with EDR for Endor Protocol and EDRCoin
'eETT': 'EETT',
'FirstBlood': '1ST',
'FORTYTWO': '42',
'LEO': 'LeoCoin',
+ 'MIOTA': 'IOTA', // https://github.com/ccxt/ccxt/issues/7487
'ORE': 'Orectic',
'PLN': 'Plutaneum', // conflict with Polish Zloty
'RUR': 'RUB',
'SCT': 'SpaceCoin',
'TPI': 'ThaneCoin',
+ 'UNUS': 'LEO', // https://github.com/ccxt/ccxt/issues/7496
'WAX': 'WAXP',
'wETT': 'WETT',
'XBT': 'Bricktox',
@@ -74143,6 +85598,13 @@ module.exports = class livecoin extends Exchange {
async fetchCurrencies (params = {}) {
const response = await this.publicGetInfoCoinInfo (params);
+ if (typeof response === 'string') {
+ if (response.indexOf ('site is under maintenance') >= 0) {
+ throw new OnMaintenance (this.id + ' fetchCurrencies() failed to fetch the currencies, the exchange is on maintenance');
+ } else {
+ throw new BadResponse (this.id + ' fetchCurrencies() failed to fetch the currencies');
+ }
+ }
const currencies = this.safeValue (response, 'info');
let result = {};
for (let i = 0; i < currencies.length; i++) {
@@ -74330,12 +85792,12 @@ module.exports = class livecoin extends Exchange {
const result = {};
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- const market = this.markets_by_id[id];
+ const market = this.safeMarket (id);
const symbol = market['symbol'];
const ticker = tickers[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -74393,21 +85855,8 @@ module.exports = class livecoin extends Exchange {
cost = amount * price;
}
}
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('/');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '/');
return {
'id': id,
'info': trade,
@@ -74532,14 +85981,8 @@ module.exports = class livecoin extends Exchange {
// let trades = this.parseTrades (order['trades'], market, since, limit);
const trades = undefined;
const status = this.parseOrderStatus (this.safeString2 (order, 'status', 'orderStatus'));
- let symbol = undefined;
- if (market === undefined) {
- let marketId = this.safeString (order, 'currencyPair');
- marketId = this.safeString (order, 'symbol', marketId);
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
+ const marketId = this.safeString2 (order, 'symbol', 'currencyPair');
+ const symbol = this.safeSymbol (marketId, market, '/');
let type = this.safeStringLower (order, 'type');
let side = undefined;
if (type !== undefined) {
@@ -74565,9 +86008,11 @@ module.exports = class livecoin extends Exchange {
if (cost !== undefined && feeRate !== undefined) {
feeCost = cost * feeRate;
}
+ if ((market === undefined) && (symbol in this.markets)) {
+ market = this.markets[symbol];
+ }
let feeCurrency = undefined;
if (market !== undefined) {
- symbol = market['symbol'];
feeCurrency = market['quote'];
}
return {
@@ -74580,8 +86025,10 @@ module.exports = class livecoin extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'filled': filled,
@@ -74882,7 +86329,7 @@ module.exports = class livecoin extends Exchange {
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],108:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],107:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -74901,20 +86348,29 @@ module.exports = class luno extends Exchange {
'rateLimit': 1000,
'version': '1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchTickers': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
},
'urls': {
'referral': 'https://www.luno.com/invite/44893A',
'logo': 'https://user-images.githubusercontent.com/1294454/27766607-8c1a69d8-5ede-11e7-930c-540b5eb9be24.jpg',
- 'api': 'https://api.mybitx.com/api',
+ 'api': 'https://api.luno.com/api',
'www': 'https://www.luno.com',
'doc': [
'https://www.luno.com/en/api',
@@ -74937,6 +86393,7 @@ module.exports = class luno extends Exchange {
'accounts/{id}/pending',
'accounts/{id}/transactions',
'balance',
+ 'beneficiaries',
'fee_info',
'funding_address',
'listorders',
@@ -74948,6 +86405,7 @@ module.exports = class luno extends Exchange {
],
'post': [
'accounts',
+ 'accounts/{id}/name',
'postorder',
'marketorder',
'stoporder',
@@ -74958,6 +86416,7 @@ module.exports = class luno extends Exchange {
'oauth2/grant',
],
'put': [
+ 'accounts/{id}/name',
'quotes/{id}',
],
'delete': [
@@ -74996,6 +86455,25 @@ module.exports = class luno extends Exchange {
return result;
}
+ async fetchAccounts (params = {}) {
+ const response = await this.privateGetBalance (params);
+ const wallets = this.safeValue (response, 'balance', []);
+ const result = [];
+ for (let i = 0; i < wallets.length; i++) {
+ const account = wallets[i];
+ const accountId = this.safeString (account, 'account_id');
+ const currencyId = this.safeString (account, 'asset');
+ const code = this.safeCurrencyCode (currencyId);
+ result.push ({
+ 'id': accountId,
+ 'type': undefined,
+ 'currency': code,
+ 'info': account,
+ });
+ }
+ return result;
+ }
+
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.privateGetBalance (params);
@@ -75032,6 +86510,14 @@ module.exports = class luno extends Exchange {
return this.parseOrderBook (response, timestamp, 'bids', 'asks', 'price', 'volume');
}
+ parseOrderStatus (status) {
+ const statuses = {
+ // todo add other statuses
+ 'PENDING': 'open',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
parseOrder (order, market = undefined) {
//
// {
@@ -75051,16 +86537,11 @@ module.exports = class luno extends Exchange {
// }
//
const timestamp = this.safeInteger (order, 'creation_timestamp');
- const status = (order['state'] === 'PENDING') ? 'open' : 'closed';
+ let status = this.parseOrderStatus (this.safeString (order, 'state'));
+ status = (status === 'open') ? status : status;
const side = (order['type'] === 'ASK') ? 'sell' : 'buy';
const marketId = this.safeString (order, 'pair');
- let symbol = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const price = this.safeFloat (order, 'limit_price');
const amount = this.safeFloat (order, 'limit_volume');
const quoteFee = this.safeFloat (order, 'fee_counter');
@@ -75095,8 +86576,10 @@ module.exports = class luno extends Exchange {
'status': status,
'symbol': symbol,
'type': undefined,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': filled,
'cost': cost,
@@ -75184,12 +86667,12 @@ module.exports = class luno extends Exchange {
const result = {};
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- const market = this.markets_by_id[id];
+ const market = this.safeMarket (id);
const symbol = market['symbol'];
const ticker = tickers[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -75337,6 +86820,146 @@ module.exports = class luno extends Exchange {
return await this.privatePostStoporder (this.extend (request, params));
}
+ async fetchLedgerByEntries (code = undefined, entry = -1, limit = 1, params = {}) {
+ // by default without entry number or limit number, return most recent entry
+ const since = undefined;
+ const request = {
+ 'min_row': entry,
+ 'max_row': this.sum (entry, limit),
+ };
+ return await this.fetchLedger (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ let currency = undefined;
+ let id = this.safeString (params, 'id'); // account id
+ let min_row = this.safeValue (params, 'min_row');
+ let max_row = this.safeValue (params, 'max_row');
+ if (id === undefined) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchLedger() requires a currency code argument if no account id specified in params');
+ }
+ currency = this.currency (code);
+ const accountsByCurrencyCode = this.indexBy (this.accounts, 'currency');
+ const account = this.safeValue (accountsByCurrencyCode, code);
+ if (account === undefined) {
+ throw new ExchangeError (this.id + ' fetchLedger() could not find account id for ' + code);
+ }
+ id = account['id'];
+ }
+ if (min_row === undefined && max_row === undefined) {
+ max_row = 0; // Default to most recent transactions
+ min_row = -1000; // Maximum number of records supported
+ } else if (min_row === undefined || max_row === undefined) {
+ throw new ExchangeError (this.id + " fetchLedger() require both params 'max_row' and 'min_row' or neither to be defined");
+ }
+ if (limit !== undefined && max_row - min_row > limit) {
+ if (max_row <= 0) {
+ min_row = max_row - limit;
+ } else if (min_row > 0) {
+ max_row = min_row + limit;
+ }
+ }
+ if (max_row - min_row > 1000) {
+ throw new ExchangeError (this.id + " fetchLedger() requires the params 'max_row' - 'min_row' <= 1000");
+ }
+ const request = {
+ 'id': id,
+ 'min_row': min_row,
+ 'max_row': max_row,
+ };
+ const response = await this.privateGetAccountsIdTransactions (this.extend (params, request));
+ const entries = this.safeValue (response, 'transactions', []);
+ return this.parseLedger (entries, currency, since, limit);
+ }
+
+ parseLedgerComment (comment) {
+ const words = comment.split (' ');
+ const types = {
+ 'Withdrawal': 'fee',
+ 'Trading': 'fee',
+ 'Payment': 'transaction',
+ 'Sent': 'transaction',
+ 'Deposit': 'transaction',
+ 'Received': 'transaction',
+ 'Released': 'released',
+ 'Reserved': 'reserved',
+ 'Sold': 'trade',
+ 'Bought': 'trade',
+ 'Failure': 'failed',
+ };
+ let referenceId = undefined;
+ const firstWord = this.safeString (words, 0);
+ const thirdWord = this.safeString (words, 2);
+ const fourthWord = this.safeString (words, 3);
+ let type = this.safeString (types, firstWord, undefined);
+ if ((type === undefined) && (thirdWord === 'fee')) {
+ type = 'fee';
+ }
+ if ((type === 'reserved') && (fourthWord === 'order')) {
+ referenceId = this.safeString (words, 4);
+ }
+ return {
+ 'type': type,
+ 'referenceId': referenceId,
+ };
+ }
+
+ parseLedgerEntry (entry, currency = undefined) {
+ // const details = this.safeValue (entry, 'details', {});
+ const id = this.safeString (entry, 'row_index');
+ const account_id = this.safeString (entry, 'account_id');
+ const timestamp = this.safeValue (entry, 'timestamp');
+ const currencyId = this.safeString (entry, 'currency');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const available_delta = this.safeFloat (entry, 'available_delta');
+ const balance_delta = this.safeFloat (entry, 'balance_delta');
+ const after = this.safeFloat (entry, 'balance');
+ const comment = this.safeString (entry, 'description');
+ let before = after;
+ let amount = 0.0;
+ const result = this.parseLedgerComment (comment);
+ const type = result['type'];
+ const referenceId = result['referenceId'];
+ let direction = undefined;
+ let status = undefined;
+ if (balance_delta !== 0.0) {
+ before = after - balance_delta; // TODO: float precision
+ status = 'ok';
+ amount = Math.abs (balance_delta);
+ } else if (available_delta < 0.0) {
+ status = 'pending';
+ amount = Math.abs (available_delta);
+ } else if (available_delta > 0.0) {
+ status = 'canceled';
+ amount = Math.abs (available_delta);
+ }
+ if (balance_delta > 0 || available_delta > 0) {
+ direction = 'in';
+ } else if (balance_delta < 0 || available_delta < 0) {
+ direction = 'out';
+ }
+ return {
+ 'id': id,
+ 'direction': direction,
+ 'account': account_id,
+ 'referenceId': referenceId,
+ 'referenceAccount': undefined,
+ 'type': type,
+ 'currency': code,
+ 'amount': amount,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'before': before,
+ 'after': after,
+ 'status': status,
+ 'fee': undefined,
+ 'info': entry,
+ };
+ }
+
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
let url = this.urls['api'] + '/' + this.version + '/' + this.implodeParams (path, params);
const query = this.omit (params, this.extractParams (path));
@@ -75345,9 +86968,10 @@ module.exports = class luno extends Exchange {
}
if (api === 'private') {
this.checkRequiredCredentials ();
- let auth = this.encode (this.apiKey + ':' + this.secret);
- auth = this.stringToBase64 (auth);
- headers = { 'Authorization': 'Basic ' + this.decode (auth) };
+ const auth = this.stringToBase64 (this.apiKey + ':' + this.secret);
+ headers = {
+ 'Authorization': 'Basic ' + this.decode (auth),
+ };
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
@@ -75361,7 +86985,7 @@ module.exports = class luno extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],109:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],108:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -75381,11 +87005,32 @@ module.exports = class lykke extends Exchange {
'has': {
'CORS': false,
'fetchOHLCV': false,
- 'fetchTrades': true,
'fetchOpenOrders': true,
'fetchClosedOrders': true,
'fetchOrder': true,
'fetchOrders': true,
+ 'fetchTrades': true,
+ 'fetchMyTrades': true,
+ 'createOrder': true,
+ 'cancelOrder': true,
+ 'cancelAllOrders': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ },
+ 'timeframes': {
+ '1m': 'Minute',
+ '5m': 'Min5',
+ '15m': 'Min15',
+ '30m': 'Min30',
+ '1h': 'Hour',
+ '4h': 'Hour4',
+ '6h': 'Hour6',
+ '12h': 'Hour12',
+ '1d': 'Day',
+ '1w': 'Week',
+ '1M': 'Month',
},
'requiredCredentials': {
'apiKey': true,
@@ -75413,8 +87058,26 @@ module.exports = class lykke extends Exchange {
'api': {
'mobile': {
'get': [
+ 'AssetPairs/rate',
+ 'AssetPairs/rate/{assetPairId}',
+ 'AssetPairs/dictionary/{market}',
+ 'Assets/dictionary',
+ 'Candles/history/{market}/available',
+ 'Candles/history/{market}/{assetPair}/{period}/{type}/{from}/{to}',
+ 'Company/ownershipStructure',
+ 'Company/registrationsCount',
+ 'IsAlive',
+ 'Market',
'Market/{market}',
+ 'Market/capitalization/{market}',
+ 'OrderBook',
+ 'OrderBook/{assetPairId}',
'Trades/{AssetPairId}',
+ 'Trades/Last/{assetPair}/{n}',
+ ],
+ 'post': [
+ 'AssetPairs/rate/history',
+ 'AssetPairs/rate/history/{assetPairId}',
],
},
'public': {
@@ -75431,11 +87094,20 @@ module.exports = class lykke extends Exchange {
'Orders',
'Orders/{id}',
'Wallets',
+ 'History/trades',
],
'post': [
'Orders/limit',
'Orders/market',
'Orders/{id}/Cancel',
+ 'Orders/v2/market',
+ 'Orders/v2/limit',
+ 'Orders/stoplimit',
+ 'Orders/bulk',
+ ],
+ 'delete': [
+ 'Orders',
+ 'Orders/{id}',
],
},
},
@@ -75477,20 +87149,45 @@ module.exports = class lykke extends Exchange {
// "action": "Buy"
// }
//
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (trade, 'AssetPairId');
- market = this.safeValue (this.markets_by_id, marketId);
+ // private fetchMyTrades
+ // {
+ // Id: '3500b83c-9963-4349-b3ee-b3e503073cea',
+ // OrderId: '83b50feb-8615-4dc6-b606-8a4168ecd708',
+ // DateTime: '2020-05-19T11:17:39.31+00:00',
+ // Timestamp: '2020-05-19T11:17:39.31+00:00',
+ // State: null,
+ // Amount: -0.004,
+ // BaseVolume: -0.004,
+ // QuotingVolume: 39.3898,
+ // Asset: 'BTC',
+ // BaseAssetId: 'BTC',
+ // QuotingAssetId: 'USD',
+ // AssetPair: 'BTCUSD',
+ // AssetPairId: 'BTCUSD',
+ // Price: 9847.427,
+ // Fee: { Amount: null, Type: 'Unknown', FeeAssetId: null }
+ // },
+ const marketId = this.safeString (trade, 'AssetPairId');
+ const symbol = this.safeSymbol (marketId, market);
+ const id = this.safeString2 (trade, 'id', 'Id');
+ const orderId = this.safeString (trade, 'OrderId');
+ const timestamp = this.parse8601 (this.safeString2 (trade, 'dateTime', 'DateTime'));
+ const price = this.safeFloat2 (trade, 'price', 'Price');
+ let amount = this.safeFloat2 (trade, 'volume', 'Amount');
+ let side = this.safeStringLower (trade, 'action');
+ if (side === undefined) {
+ if (amount < 0) {
+ side = 'sell';
+ } else {
+ side = 'buy';
+ }
}
- if (market) {
- symbol = market['symbol'];
- }
- const id = this.safeString (trade, 'id');
- const timestamp = this.parse8601 (this.safeString (trade, 'dateTime'));
- const side = this.safeStringLower (trade, 'action');
- const price = this.safeFloat (trade, 'price');
- const amount = this.safeFloat (trade, 'volume');
+ amount = Math.abs (amount);
const cost = price * amount;
+ const fee = {
+ 'cost': 0, // There are no fees for trading. https://www.lykke.com/wallet-fees-and-limits/
+ 'currency': market['quote'],
+ };
return {
'id': id,
'info': trade,
@@ -75498,13 +87195,13 @@ module.exports = class lykke extends Exchange {
'datetime': this.iso8601 (timestamp),
'symbol': symbol,
'type': undefined,
- 'order': undefined,
+ 'order': orderId,
'side': side,
'takerOrMaker': undefined,
'price': price,
'amount': amount,
'cost': cost,
- 'fee': undefined,
+ 'fee': fee,
};
}
@@ -75523,6 +87220,21 @@ module.exports = class lykke extends Exchange {
return this.parseTrades (response, market, since, limit);
}
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (limit !== undefined) {
+ request['take'] = limit; // How many maximum items have to be returned, max 1000 default 100.
+ }
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['assetPairId'] = market['id'];
+ }
+ const response = await this.privateGetHistoryTrades (this.extend (request, params));
+ return this.parseTrades (response, market, since, limit);
+ }
+
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.privateGetWallets (params);
@@ -75540,7 +87252,19 @@ module.exports = class lykke extends Exchange {
}
async cancelOrder (id, symbol = undefined, params = {}) {
- return await this.privatePostOrdersIdCancel ({ 'id': id });
+ const request = { 'id': id };
+ return await this.privateDeleteOrdersId (this.extend (request, params));
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['assetPairId'] = market['id'];
+ }
+ return await this.privateDeleteOrders (this.extend (request, params));
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
@@ -75550,17 +87274,47 @@ module.exports = class lykke extends Exchange {
'AssetPairId': market['id'],
'OrderAction': this.capitalize (side),
'Volume': amount,
+ 'Asset': market['baseId'],
};
- if (type === 'market') {
- query['Asset'] = (side === 'buy') ? market['base'] : market['quote'];
- } else if (type === 'limit') {
+ if (type === 'limit') {
query['Price'] = price;
}
- const method = 'privatePostOrders' + this.capitalize (type);
+ const method = 'privatePostOrdersV2' + this.capitalize (type);
const result = await this[method] (this.extend (query, params));
+ //
+ // market
+ //
+ // {
+ // "Price": 0
+ // }
+ //
+ // limit
+ //
+ // {
+ // "Id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ // }
+ //
+ const id = this.safeString (result, 'Id');
+ price = this.safeFloat (result, 'Price');
return {
- 'id': undefined,
+ 'id': id,
'info': result,
+ 'clientOrderId': undefined,
+ 'timestamp': undefined,
+ 'datetime': undefined,
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': undefined,
+ 'average': undefined,
+ 'filled': undefined,
+ 'remaining': undefined,
+ 'status': undefined,
+ 'fee': undefined,
+ 'trades': undefined,
};
}
@@ -75594,8 +87348,8 @@ module.exports = class lykke extends Exchange {
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
const precision = {
- 'amount': this.safeInteger (market, 'Accuracy'),
- 'price': this.safeInteger (market, 'InvertedAccuracy'),
+ 'price': this.safeInteger (market, 'Accuracy'),
+ 'amount': this.safeInteger (market, 'InvertedAccuracy'),
};
result.push ({
'id': id,
@@ -75677,6 +87431,7 @@ module.exports = class lykke extends Exchange {
'Cancelled': 'canceled',
'Rejected': 'rejected',
'Replaced': 'canceled',
+ 'Placed': 'open',
};
return this.safeString (statuses, status, status);
}
@@ -75700,14 +87455,8 @@ module.exports = class lykke extends Exchange {
// }
//
const status = this.parseOrderStatus (this.safeString (order, 'Status'));
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'AssetPairId');
- market = this.safeValue (this.markets_by_id, marketId);
- }
- if (market) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'AssetPairId');
+ const symbol = this.safeSymbol (marketId, market);
const lastTradeTimestamp = this.parse8601 (this.safeString (order, 'LastMatchTime'));
let timestamp = undefined;
if (('Registered' in order) && (order['Registered'])) {
@@ -75716,8 +87465,15 @@ module.exports = class lykke extends Exchange {
timestamp = this.parse8601 (order['CreatedAt']);
}
const price = this.safeFloat (order, 'Price');
- const amount = this.safeFloat (order, 'Volume');
- const remaining = this.safeFloat (order, 'RemainingVolume');
+ let side = undefined;
+ let amount = this.safeFloat (order, 'Volume');
+ if (amount < 0) {
+ side = 'sell';
+ amount = Math.abs (amount);
+ } else {
+ side = 'buy';
+ }
+ const remaining = Math.abs (this.safeFloat (order, 'RemainingVolume'));
const filled = amount - remaining;
const cost = filled * price;
const id = this.safeString (order, 'Id');
@@ -75730,8 +87486,10 @@ module.exports = class lykke extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': undefined,
- 'side': undefined,
+ 'timeInForce': undefined,
+ 'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': undefined,
'amount': amount,
@@ -75755,25 +87513,25 @@ module.exports = class lykke extends Exchange {
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privateGetOrders (params);
- return this.parseOrders (response, undefined, since, limit);
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ return this.parseOrders (response, market, since, limit);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
const request = {
'status': 'InOrderBook',
};
- const response = await this.privateGetOrders (this.extend (request, params));
- return this.parseOrders (response, undefined, since, limit);
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
}
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
const request = {
'status': 'Matched',
};
- const response = await this.privateGetOrders (this.extend (request, params));
- return this.parseOrders (response, undefined, since, limit);
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -75821,7 +87579,7 @@ module.exports = class lykke extends Exchange {
url += '?' + this.urlencode (query);
}
} else if (api === 'private') {
- if (method === 'GET') {
+ if ((method === 'GET') || (method === 'DELETE')) {
if (Object.keys (query).length) {
url += '?' + this.urlencode (query);
}
@@ -75842,7 +87600,7 @@ module.exports = class lykke extends Exchange {
}
};
-},{"./base/Exchange":7}],110:[function(require,module,exports){
+},{"./base/Exchange":5}],109:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -75861,15 +87619,20 @@ module.exports = class mercado extends Exchange {
'rateLimit': 1000,
'version': 'v3',
'has': {
+ 'cancelOrder': true,
'CORS': true,
'createMarketOrder': true,
- 'fetchOrder': true,
- 'withdraw': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchOHLCV': true,
- 'fetchOrders': true,
'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
'fetchTicker': true,
'fetchTickers': false,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1m',
@@ -75936,6 +87699,7 @@ module.exports = class mercado extends Exchange {
'BCH/BRL': { 'id': 'BRLBCH', 'symbol': 'BCH/BRL', 'base': 'BCH', 'quote': 'BRL', 'precision': { 'amount': 8, 'price': 5 }, 'suffix': 'BCash' },
'XRP/BRL': { 'id': 'BRLXRP', 'symbol': 'XRP/BRL', 'base': 'XRP', 'quote': 'BRL', 'precision': { 'amount': 8, 'price': 5 }, 'suffix': 'Ripple' },
'ETH/BRL': { 'id': 'BRLETH', 'symbol': 'ETH/BRL', 'base': 'ETH', 'quote': 'BRL', 'precision': { 'amount': 8, 'price': 5 }, 'suffix': 'Ethereum' },
+ 'USDC/BRL': { 'id': 'BRLUSDC', 'symbol': 'USDC/BRL', 'base': 'USDC', 'quote': 'BRL', 'precision': { 'amount': 8, 'price': 5 }, 'suffix': 'USDC' },
},
'fees': {
'trading': {
@@ -76173,14 +87937,8 @@ module.exports = class mercado extends Exchange {
side = (order['order_type'] === 1) ? 'buy' : 'sell';
}
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'coin_pair');
- market = this.safeValue (this.markets_by_id, marketId);
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'coin_pair');
+ market = this.safeMarket (marketId, market);
const timestamp = this.safeTimestamp (order, 'created_timestamp');
const fee = {
'cost': this.safeFloat (order, 'fee'),
@@ -76201,10 +87959,12 @@ module.exports = class mercado extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -76268,7 +88028,7 @@ module.exports = class mercado extends Exchange {
};
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
return [
this.safeTimestamp (ohlcv, 'timestamp'),
this.safeFloat (ohlcv, 'open'),
@@ -76351,7 +88111,7 @@ module.exports = class mercado extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],111:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],110:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -76371,10 +88131,16 @@ module.exports = class mixcoins extends Exchange {
'version': 'v1',
'userAgent': this.userAgents['chrome'],
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/30237212-ed29303c-9535-11e7-8af8-fcd381cfa20c.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87460810-1dd06c00-c616-11ea-9276-956f400d6ffa.jpg',
'api': 'https://mixcoins.com/api',
'www': 'https://mixcoins.com',
'doc': 'https://mixcoins.com/help/api/',
@@ -76576,7 +88342,1197 @@ module.exports = class mixcoins extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],112:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],111:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { AuthenticationError, ExchangeError, PermissionDenied, BadRequest, CancelPending, OrderNotFound, InsufficientFunds, RateLimitExceeded, InvalidOrder, AccountSuspended, BadSymbol, OnMaintenance } = require ('./base/errors');
+const { TRUNCATE } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class novadax extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'novadax',
+ 'name': 'NovaDAX',
+ 'countries': [ 'BR' ], // Brazil
+ 'rateLimit': 50,
+ 'version': 'v1',
+ // new metainfo interface
+ 'has': {
+ 'CORS': false,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrders': true,
+ 'fetchOrderTrades': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
+ },
+ 'timeframes': {
+ '1m': 'ONE_MIN',
+ '5m': 'FIVE_MIN',
+ '15m': 'FIFTEEN_MIN',
+ '30m': 'HALF_HOU',
+ '1h': 'ONE_HOU',
+ '1d': 'ONE_DAY',
+ '1w': 'ONE_WEE',
+ '1M': 'ONE_MON',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/92337550-2b085500-f0b3-11ea-98e7-5794fb07dd3b.jpg',
+ 'api': {
+ 'public': 'https://api.novadax.com',
+ 'private': 'https://api.novadax.com',
+ },
+ 'www': 'https://www.novadax.com.br',
+ 'doc': [
+ 'https://doc.novadax.com/pt-BR/',
+ ],
+ 'fees': 'https://www.novadax.com.br/fees-and-limits',
+ 'referral': 'https://www.novadax.com.br/?s=ccxt',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'common/symbol',
+ 'common/symbols',
+ 'common/timestamp',
+ 'market/tickers',
+ 'market/ticker',
+ 'market/depth',
+ 'market/trades',
+ 'market/kline/history',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'orders/get',
+ 'orders/list',
+ 'orders/fill',
+ 'orders/fills',
+ 'account/getBalance',
+ 'account/subs',
+ 'account/subs/balance',
+ 'account/subs/transfer/record',
+ 'wallet/query/deposit-withdraw',
+ ],
+ 'post': [
+ 'orders/create',
+ 'orders/cancel',
+ 'account/withdraw/coin',
+ 'account/subs/transfer',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': false,
+ 'percentage': true,
+ 'taker': 0.5 / 100,
+ 'maker': 0.3 / 100,
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ },
+ 'exceptions': {
+ 'exact': {
+ 'A99999': ExchangeError, // 500 Failed Internal error
+ // 'A10000': ExchangeError, // 200 Success Successful request
+ 'A10001': BadRequest, // 400 Params error Parameter is invalid
+ 'A10002': ExchangeError, // 404 Api not found API used is irrelevant
+ 'A10003': AuthenticationError, // 403 Authentication failed Authentication is failed
+ 'A10004': RateLimitExceeded, // 429 Too many requests Too many requests are made
+ 'A10005': PermissionDenied, // 403 Kyc required Need to complete KYC firstly
+ 'A10006': AccountSuspended, // 403 Customer canceled Account is canceled
+ 'A10007': BadRequest, // 400 Account not exist Sub account does not exist
+ 'A10011': BadSymbol, // 400 Symbol not exist Trading symbol does not exist
+ 'A10012': BadSymbol, // 400 Symbol not trading Trading symbol is temporarily not available
+ 'A10013': OnMaintenance, // 503 Symbol maintain Trading symbol is in maintain
+ 'A30001': OrderNotFound, // 400 Order not found Queried order is not found
+ 'A30002': InvalidOrder, // 400 Order amount is too small Order amount is too small
+ 'A30003': InvalidOrder, // 400 Order amount is invalid Order amount is invalid
+ 'A30004': InvalidOrder, // 400 Order value is too small Order value is too small
+ 'A30005': InvalidOrder, // 400 Order value is invalid Order value is invalid
+ 'A30006': InvalidOrder, // 400 Order price is invalid Order price is invalid
+ 'A30007': InsufficientFunds, // 400 Insufficient balance The balance is insufficient
+ 'A30008': InvalidOrder, // 400 Order was closed The order has been executed
+ 'A30009': InvalidOrder, // 400 Order canceled The order has been cancelled
+ 'A30010': CancelPending, // 400 Order cancelling The order is being cancelled
+ 'A30011': InvalidOrder, // 400 Order price too high The order price is too high
+ 'A30012': InvalidOrder, // 400 Order price too low The order price is too low
+ },
+ 'broad': {
+ },
+ },
+ 'options': {
+ 'fetchOHLCV': {
+ 'volume': 'amount', // 'amount' for base volume or 'vol' for quote volume
+ },
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetCommonTimestamp (params);
+ //
+ // {
+ // "code":"A10000",
+ // "data":1599090512080,
+ // "message":"Success"
+ // }
+ //
+ return this.safeInteger (response, 'data');
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetCommonSymbols (params);
+ //
+ // {
+ // "code":"A10000",
+ // "data":[
+ // {
+ // "amountPrecision":8,
+ // "baseCurrency":"BTC",
+ // "minOrderAmount":"0.001",
+ // "minOrderValue":"25",
+ // "pricePrecision":2,
+ // "quoteCurrency":"BRL",
+ // "status":"ONLINE",
+ // "symbol":"BTC_BRL",
+ // "valuePrecision":2
+ // },
+ // ],
+ // "message":"Success"
+ // }
+ //
+ const result = [];
+ const data = this.safeValue (response, 'data', []);
+ for (let i = 0; i < data.length; i++) {
+ const market = data[i];
+ const baseId = this.safeString (market, 'baseCurrency');
+ const quoteId = this.safeString (market, 'quoteCurrency');
+ const id = this.safeString (market, 'symbol');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const precision = {
+ 'amount': this.safeInteger (market, 'amountPrecision'),
+ 'price': this.safeInteger (market, 'pricePrecision'),
+ 'cost': this.safeInteger (market, 'valuePrecision'),
+ };
+ const limits = {
+ 'amount': {
+ 'min': this.safeFloat (market, 'minOrderAmount'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': this.safeFloat (market, 'minOrderValue'),
+ 'max': undefined,
+ },
+ };
+ const status = this.safeString (market, 'status');
+ const active = (status === 'ONLINE');
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'precision': precision,
+ 'limits': limits,
+ 'info': market,
+ 'active': active,
+ });
+ }
+ return result;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker, fetchTickers
+ //
+ // {
+ // "ask":"61946.1",
+ // "baseVolume24h":"164.41930186",
+ // "bid":"61815",
+ // "high24h":"64930.72",
+ // "lastPrice":"61928.41",
+ // "low24h":"61156.32",
+ // "open24h":"64512.46",
+ // "quoteVolume24h":"10308157.95",
+ // "symbol":"BTC_BRL",
+ // "timestamp":1599091115090
+ // }
+ //
+ const timestamp = this.safeInteger (ticker, 'timestamp');
+ const marketId = this.safeString (ticker, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const open = this.safeFloat (ticker, 'open24h');
+ const last = this.safeFloat (ticker, 'lastPrice');
+ let percentage = undefined;
+ let change = undefined;
+ let average = undefined;
+ if ((last !== undefined) && (open !== undefined)) {
+ change = last - open;
+ percentage = change / open * 100;
+ average = this.sum (last, open) / 2;
+ }
+ const baseVolume = this.safeFloat (ticker, 'baseVolume24h');
+ const quoteVolume = this.safeFloat (ticker, 'quoteVolume24h');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high24h'),
+ 'low': this.safeFloat (ticker, 'low24h'),
+ 'bid': this.safeFloat (ticker, 'bid'),
+ 'bidVolume': undefined,
+ 'ask': this.safeFloat (ticker, 'ask'),
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this.publicGetMarketTicker (this.extend (request, params));
+ //
+ // {
+ // "code":"A10000",
+ // "data":{
+ // "ask":"61946.1",
+ // "baseVolume24h":"164.41930186",
+ // "bid":"61815",
+ // "high24h":"64930.72",
+ // "lastPrice":"61928.41",
+ // "low24h":"61156.32",
+ // "open24h":"64512.46",
+ // "quoteVolume24h":"10308157.95",
+ // "symbol":"BTC_BRL",
+ // "timestamp":1599091115090
+ // },
+ // "message":"Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTicker (data, market);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetMarketTickers (params);
+ //
+ // {
+ // "code":"A10000",
+ // "data":[
+ // {
+ // "ask":"61879.36",
+ // "baseVolume24h":"164.40955092",
+ // "bid":"61815",
+ // "high24h":"64930.72",
+ // "lastPrice":"61820.04",
+ // "low24h":"61156.32",
+ // "open24h":"64624.19",
+ // "quoteVolume24h":"10307493.92",
+ // "symbol":"BTC_BRL",
+ // "timestamp":1599091291083
+ // },
+ // ],
+ // "message":"Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = {};
+ for (let i = 0; i < data.length; i++) {
+ const ticker = this.parseTicker (data[i]);
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'symbol': this.marketId (symbol),
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 10, max 20
+ }
+ const response = await this.publicGetMarketDepth (this.extend (request, params));
+ //
+ // {
+ // "code":"A10000",
+ // "data":{
+ // "asks":[
+ // ["0.037159","0.3741"],
+ // ["0.037215","0.2706"],
+ // ["0.037222","1.8459"],
+ // ],
+ // "bids":[
+ // ["0.037053","0.3857"],
+ // ["0.036969","0.8101"],
+ // ["0.036953","1.5226"],
+ // ],
+ // "timestamp":1599280414448
+ // },
+ // "message":"Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const timestamp = this.safeInteger (data, 'timestamp');
+ return this.parseOrderBook (data, timestamp, 'bids', 'asks');
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades
+ //
+ // {
+ // "amount":"0.0632",
+ // "price":"0.037288",
+ // "side":"BUY",
+ // "timestamp":1599279694576
+ // }
+ //
+ // private fetchOrderTrades
+ //
+ // {
+ // "id": "608717046691139584",
+ // "orderId": "608716957545402368",
+ // "symbol": "BTC_BRL",
+ // "side": "BUY",
+ // "amount": "0.0988",
+ // "price": "45514.76",
+ // "fee": "0.0000988 BTC",
+ // "role": "MAKER",
+ // "timestamp": 1565171053345
+ // }
+ //
+ // private fetchMyTrades
+ //
+ // {
+ // "id": "608717046691139584",
+ // "orderId": "608716957545402368",
+ // "symbol": "BTC_BRL",
+ // "side": "BUY",
+ // "amount": "0.0988",
+ // "price": "45514.76",
+ // "fee": "0.0000988 BTC",
+ // "feeAmount": "0.0000988",
+ // "feeCurrency": "BTC",
+ // "role": "MAKER",
+ // "timestamp": 1565171053345
+ // }
+ //
+ const id = this.safeString (trade, 'id');
+ const orderId = this.safeString (trade, 'orderId');
+ const timestamp = this.safeInteger (trade, 'timestamp');
+ const side = this.safeStringLower (trade, 'side');
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'amount');
+ let cost = this.safeFloat (trade, 'volume');
+ if ((cost === undefined) && (amount !== undefined) && (price !== undefined)) {
+ cost = amount * price;
+ }
+ const marketId = this.safeString (trade, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const takerOrMaker = this.safeStringLower (trade, 'role');
+ const feeString = this.safeString (trade, 'fee');
+ let fee = undefined;
+ if (feeString !== undefined) {
+ const parts = feeString.split (' ');
+ const feeCurrencyId = this.safeString (parts, 1);
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': this.safeFloat (parts, 0),
+ 'currency': feeCurrencyCode,
+ };
+ }
+ return {
+ 'id': id,
+ 'order': orderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'type': undefined,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'takerOrMaker': takerOrMaker,
+ 'fee': fee,
+ 'info': trade,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 100
+ }
+ const response = await this.publicGetMarketTrades (this.extend (request, params));
+ //
+ // {
+ // "code":"A10000",
+ // "data":[
+ // {"amount":"0.0632","price":"0.037288","side":"BUY","timestamp":1599279694576},
+ // {"amount":"0.0052","price":"0.03715","side":"SELL","timestamp":1599276606852},
+ // {"amount":"0.0058","price":"0.037188","side":"SELL","timestamp":1599275187812},
+ // ],
+ // "message":"Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ 'unit': this.timeframes[timeframe],
+ };
+ const duration = this.parseTimeframe (timeframe);
+ const now = this.seconds ();
+ if (limit === undefined) {
+ limit = 3000; // max
+ }
+ if (since === undefined) {
+ request['from'] = now - limit * duration;
+ request['to'] = now;
+ } else {
+ const startFrom = parseInt (since / 1000);
+ request['from'] = startFrom;
+ request['to'] = this.sum (startFrom, limit * duration);
+ }
+ const response = await this.publicGetMarketKlineHistory (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "amount": 8.25709100,
+ // "closePrice": 62553.20,
+ // "count": 29,
+ // "highPrice": 62592.87,
+ // "lowPrice": 62553.20,
+ // "openPrice": 62554.23,
+ // "score": 1602501480,
+ // "symbol": "BTC_BRL",
+ // "vol": 516784.2504067500
+ // }
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "amount": 8.25709100,
+ // "closePrice": 62553.20,
+ // "count": 29,
+ // "highPrice": 62592.87,
+ // "lowPrice": 62553.20,
+ // "openPrice": 62554.23,
+ // "score": 1602501480,
+ // "symbol": "BTC_BRL",
+ // "vol": 516784.2504067500
+ // }
+ //
+ const options = this.safeValue (this.options, 'fetchOHLCV', {});
+ const volumeField = this.safeString (options, 'volume', 'amount'); // or vol
+ return [
+ this.safeTimestamp (ohlcv, 'score'),
+ this.safeFloat (ohlcv, 'openPrice'),
+ this.safeFloat (ohlcv, 'highPrice'),
+ this.safeFloat (ohlcv, 'lowPrice'),
+ this.safeFloat (ohlcv, 'closePrice'),
+ this.safeFloat (ohlcv, volumeField),
+ ];
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccountGetBalance (params);
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "available": "1.23",
+ // "balance": "0.23",
+ // "currency": "BTC",
+ // "hold": "1"
+ // }
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = { 'info': response };
+ for (let i = 0; i < data.length; i++) {
+ const balance = data[i];
+ const currencyId = this.safeString (balance, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['total'] = this.safeFloat (balance, 'available');
+ account['free'] = this.safeFloat (balance, 'balance');
+ account['used'] = this.safeFloat (balance, 'hold');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const uppercaseType = type.toUpperCase ();
+ const uppercaseSide = side.toUpperCase ();
+ const request = {
+ 'symbol': market['id'],
+ 'type': uppercaseType, // LIMIT, MARKET
+ 'side': uppercaseSide, // or SELL
+ // 'accountId': '...', // subaccount id, optional
+ // 'amount': this.amountToPrecision (symbol, amount),
+ // "price": "1234.5678", // required for LIMIT and STOP orders
+ };
+ if (uppercaseType === 'LIMIT') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ } else if (uppercaseType === 'MARKET') {
+ if (uppercaseSide === 'SELL') {
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ } else if (uppercaseSide === 'BUY') {
+ let value = this.safeFloat (params, 'value');
+ const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true);
+ if (createMarketBuyOrderRequiresPrice) {
+ if (price !== undefined) {
+ if (value === undefined) {
+ value = amount * price;
+ }
+ } else if (value === undefined) {
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument or in the 'value' extra parameter (the exchange-specific behaviour)");
+ }
+ } else {
+ value = (value === undefined) ? amount : value;
+ }
+ const precision = market['precision']['price'];
+ request['value'] = this.decimalToPrecision (value, TRUNCATE, precision, this.precisionMode);
+ }
+ }
+ const response = await this.privatePostOrdersCreate (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": {
+ // "amount": "0.001",
+ // "averagePrice": null,
+ // "filledAmount": "0",
+ // "filledFee": "0",
+ // "filledValue": "0",
+ // "id": "633679992971251712",
+ // "price": "35000",
+ // "side": "BUY",
+ // "status": "PROCESSING",
+ // "symbol": "BTC_BRL",
+ // "timestamp": 1571122683535,
+ // "type": "LIMIT",
+ // "value": "35"
+ // },
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const response = await this.privatePostOrdersCancel (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": {
+ // "result": true
+ // },
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const response = await this.privateGetOrdersGet (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": {
+ // "id": "608695623247466496",
+ // "symbol": "BTC_BRL",
+ // "type": "MARKET",
+ // "side": "SELL",
+ // "price": null,
+ // "averagePrice": "0",
+ // "amount": "0.123",
+ // "filledAmount": "0",
+ // "value": null,
+ // "filledValue": "0",
+ // "filledFee": "0",
+ // "status": "REJECTED",
+ // "timestamp": 1565165945588
+ // },
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data);
+ }
+
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'symbol': market['id'],
+ // 'status': 'SUBMITTED,PROCESSING', // SUBMITTED, PROCESSING, PARTIAL_FILLED, CANCELING, FILLED, CANCELED, REJECTED
+ // 'fromId': '...', // order id to begin with
+ // 'toId': '...', // order id to end up with
+ // 'fromTimestamp': since,
+ // 'toTimestamp': this.milliseconds (),
+ // 'limit': limit, // default 100, max 100
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 100, max 100
+ }
+ if (since !== undefined) {
+ request['fromTimestamp'] = since;
+ }
+ const response = await this.privateGetOrdersList (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "id": "608695678650028032",
+ // "symbol": "BTC_BRL",
+ // "type": "MARKET",
+ // "side": "SELL",
+ // "price": null,
+ // "averagePrice": "0",
+ // "amount": "0.123",
+ // "filledAmount": "0",
+ // "value": null,
+ // "filledValue": "0",
+ // "filledFee": "0",
+ // "status": "REJECTED",
+ // "timestamp": 1565165958796
+ // },
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOrders (data, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'status': 'SUBMITTED,PROCESSING,PARTIAL_FILLED,CANCELING',
+ };
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'status': 'FILLED,CANCELED,REJECTED',
+ };
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const response = await this.privateGetOrdersFill (this.extend (request, params));
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ const data = this.safeValue (response, 'data', []);
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "id": "608717046691139584",
+ // "orderId": "608716957545402368",
+ // "symbol": "BTC_BRL",
+ // "side": "BUY",
+ // "amount": "0.0988",
+ // "price": "45514.76",
+ // "fee": "0.0000988 BTC",
+ // "role": "MAKER",
+ // "timestamp": 1565171053345
+ // },
+ // ],
+ // "message": "Success"
+ // }
+ //
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'SUBMITTED': 'open',
+ 'PROCESSING': 'open',
+ 'PARTIAL_FILLED': 'open',
+ 'CANCELING': 'open',
+ 'FILLED': 'closed',
+ 'CANCELED': 'canceled',
+ 'REJECTED': 'rejected',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder, fetchOrders, fetchOrder
+ //
+ // {
+ // "amount": "0.001",
+ // "averagePrice": null,
+ // "filledAmount": "0",
+ // "filledFee": "0",
+ // "filledValue": "0",
+ // "id": "633679992971251712",
+ // "price": "35000",
+ // "side": "BUY",
+ // "status": "PROCESSING",
+ // "symbol": "BTC_BRL",
+ // "timestamp": 1571122683535,
+ // "type": "LIMIT",
+ // "value": "35"
+ // }
+ //
+ // cancelOrder
+ //
+ // {
+ // "result": true
+ // }
+ //
+ const id = this.safeString (order, 'id');
+ const amount = this.safeFloat (order, 'amount');
+ const price = this.safeFloat (order, 'price');
+ const cost = this.safeFloat (order, 'filledValue');
+ const type = this.safeStringLower (order, 'type');
+ const side = this.safeStringLower (order, 'side');
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const timestamp = this.safeInteger (order, 'timestamp');
+ const average = this.safeFloat (order, 'averagePrice');
+ const filled = this.safeFloat (order, 'filledAmount');
+ let remaining = undefined;
+ if ((amount !== undefined) && (filled !== undefined)) {
+ remaining = Math.max (0, amount - filled);
+ }
+ let fee = undefined;
+ const feeCost = this.safeFloat (order, 'filledFee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': undefined,
+ };
+ }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ return {
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'info': order,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': undefined,
+ };
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'code': currency['id'],
+ 'amount': this.currencyToPrecision (code, amount),
+ 'wallet': address,
+ };
+ if (tag !== undefined) {
+ request['tag'] = tag;
+ }
+ const response = await this.privatePostAccountWithdrawCoin (this.extend (request, params));
+ //
+ // {
+ // "code":"A10000",
+ // "data": "DR123",
+ // "message":"Success"
+ // }
+ //
+ return this.parseTransaction (response, currency);
+ }
+
+ async fetchAccounts (params = {}) {
+ const response = await this.privateGetAccountSubs (params);
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "subId": "CA648856083527372800",
+ // "state": "Normal",
+ // "subAccount": "003",
+ // "subIdentify": "003"
+ // }
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = [];
+ for (let i = 0; i < data.length; i++) {
+ const account = data[i];
+ const accountId = this.safeString (account, 'subId');
+ const type = this.safeString (account, 'subAccount');
+ result.push ({
+ 'id': accountId,
+ 'type': type,
+ 'currency': undefined,
+ 'info': account,
+ });
+ }
+ return result;
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'type': 'coin_in',
+ };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'type': 'coin_out',
+ };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'currency': currency['id'],
+ // 'type': 'coin_in', // 'coin_out'
+ // 'direct': 'asc', // 'desc'
+ // 'size': limit, // default 100
+ // 'start': id, // offset id
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency'] = currency['id'];
+ }
+ if (limit !== undefined) {
+ request['size'] = limit;
+ }
+ const response = await this.privateGetWalletQueryDepositWithdraw (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "id": "DR562339304588709888",
+ // "type": "COIN_IN",
+ // "currency": "XLM",
+ // "chain": "XLM",
+ // "address": "GCUTK7KHPJC3ZQJ3OMWWFHAK2OXIBRD4LNZQRCCOVE7A2XOPP2K5PU5Q",
+ // "addressTag": "1000009",
+ // "amount": 1.0,
+ // "state": "SUCCESS",
+ // "txHash": "39210645748822f8d4ce673c7559aa6622e6e9cdd7073bc0fcae14b1edfda5f4",
+ // "createdAt": 1554113737000,
+ // "updatedAt": 1601371273000
+ // }
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTransactions (data, currency, since, limit);
+ }
+
+ parseTransactionStatus (status) {
+ // Pending the record is wait broadcast to chain
+ // x/M confirming the comfirming state of tx, the M is total confirmings needed
+ // SUCCESS the record is success full
+ // FAIL the record failed
+ const parts = status.split (' ');
+ status = this.safeString (parts, 1, status);
+ const statuses = {
+ 'Pending': 'pending',
+ 'confirming': 'pending',
+ 'SUCCESS': 'ok',
+ 'FAIL': 'failed',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // withdraw
+ //
+ // {
+ // "code":"A10000",
+ // "data": "DR123",
+ // "message":"Success"
+ // }
+ //
+ // fetchTransactions
+ //
+ // {
+ // "id": "DR562339304588709888",
+ // "type": "COIN_IN",
+ // "currency": "XLM",
+ // "chain": "XLM",
+ // "address": "GCUTK7KHPJC3ZQJ3OMWWFHAK2OXIBRD4LNZQRCCOVE7A2XOPP2K5PU5Q",
+ // "addressTag": "1000009",
+ // "amount": 1.0,
+ // "state": "SUCCESS",
+ // "txHash": "39210645748822f8d4ce673c7559aa6622e6e9cdd7073bc0fcae14b1edfda5f4",
+ // "createdAt": 1554113737000,
+ // "updatedAt": 1601371273000
+ // }
+ //
+ const id = this.safeString2 (transaction, 'id', 'data');
+ let type = this.safeString (transaction, 'type');
+ if (type === 'COIN_IN') {
+ type = 'deposit';
+ } else if (type === 'COIN_OUT') {
+ type = 'withdraw';
+ }
+ const amount = this.safeFloat (transaction, 'amount');
+ const address = this.safeString (transaction, 'address');
+ const tag = this.safeString (transaction, 'addressTag');
+ const txid = this.safeString (transaction, 'txHash');
+ const timestamp = this.safeInteger (transaction, 'createdAt');
+ const updated = this.safeInteger (transaction, 'updatedAt');
+ const currencyId = this.safeString (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'state'));
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': code,
+ 'amount': amount,
+ 'address': address,
+ 'addressTo': address,
+ 'addressFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'tagFrom': undefined,
+ 'status': status,
+ 'type': type,
+ 'updated': updated,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': undefined,
+ };
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'orderId': id, // Order ID, string
+ // 'symbol': market['id'], // The trading symbol, like BTC_BRL, string
+ // 'fromId': fromId, // Search fill id to begin with, string
+ // 'toId': toId, // Search fill id to end up with, string
+ // 'fromTimestamp': since, // Search order fill time to begin with, in milliseconds, string
+ // 'toTimestamp': this.milliseconds (), // Search order fill time to end up with, in milliseconds, string
+ // 'limit': limit, // The number of fills to return, default 100, max 100, string
+ // 'accountId': subaccountId, // Sub account ID, if not informed, the fills will be return under master account, string
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ if (since !== undefined) {
+ request['fromTimestamp'] = since;
+ }
+ const response = await this.privateGetOrdersFills (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "id": "608717046691139584",
+ // "orderId": "608716957545402368",
+ // "symbol": "BTC_BRL",
+ // "side": "BUY",
+ // "amount": "0.0988",
+ // "price": "45514.76",
+ // "fee": "0.0000988 BTC",
+ // "feeAmount": "0.0000988",
+ // "feeCurrency": "BTC",
+ // "role": "MAKER",
+ // "timestamp": 1565171053345
+ // },
+ // {
+ // "id": "608717065729085441",
+ // "orderId": "608716957545402368",
+ // "symbol": "BTC_BRL",
+ // "side": "BUY",
+ // "amount": "0.0242",
+ // "price": "45514.76",
+ // "fee": "0.0000242 BTC",
+ // "feeAmount": "0.0000988",
+ // "feeCurrency": "BTC",
+ // "role": "MAKER",
+ // "timestamp": 1565171057882
+ // }
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const request = '/' + this.version + '/' + this.implodeParams (path, params);
+ let url = this.urls['api'][api] + request;
+ const query = this.omit (params, this.extractParams (path));
+ if (api === 'public') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (api === 'private') {
+ this.checkRequiredCredentials ();
+ const timestamp = this.milliseconds ().toString ();
+ headers = {
+ 'X-Nova-Access-Key': this.apiKey,
+ 'X-Nova-Timestamp': timestamp,
+ };
+ let queryString = undefined;
+ if (method === 'POST') {
+ body = this.json (query);
+ queryString = this.hash (body, 'md5');
+ headers['Content-Type'] = 'application/json';
+ } else {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ queryString = this.urlencode (this.keysort (query));
+ }
+ const auth = method + "\n" + request + "\n" + queryString + "\n" + timestamp; // eslint-disable-line quotes
+ headers['X-Nova-Signature'] = this.hmac (this.encode (auth), this.encode (this.secret));
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return;
+ }
+ //
+ // {"code":"A10003","data":[],"message":"Authentication failed, Invalid accessKey."}
+ //
+ const errorCode = this.safeString (response, 'code');
+ if (errorCode !== 'A10000') {
+ const message = this.safeString (response, 'message');
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],112:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -76808,11 +89764,11 @@ module.exports = class oceanex extends Exchange {
for (let i = 0; i < data.length; i++) {
const ticker = data[i];
const marketId = this.safeString (ticker, 'market');
- const market = this.markets_by_id[marketId];
+ const market = this.safeMarket (marketId);
const symbol = market['symbol'];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
parseTicker (data, market = undefined) {
@@ -76930,8 +89886,7 @@ module.exports = class oceanex extends Exchange {
for (let i = 0; i < data.length; i++) {
const orderbook = data[i];
const marketId = this.safeString (orderbook, 'market');
- const market = this.markets_by_id[marketId];
- const symbol = market['symbol'];
+ const symbol = this.safeSymbol (marketId);
const timestamp = this.safeTimestamp (orderbook, 'timestamp');
result[symbol] = this.parseOrderBook (orderbook, timestamp);
}
@@ -76959,21 +89914,8 @@ module.exports = class oceanex extends Exchange {
} else if (side === 'ask') {
side = 'sell';
}
- let symbol = undefined;
const marketId = this.safeValue (trade, 'market');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market);
let timestamp = this.safeTimestamp (trade, 'created_on');
if (timestamp === undefined) {
timestamp = this.parse8601 (this.safeString (trade, 'created_at'));
@@ -77012,10 +89954,7 @@ module.exports = class oceanex extends Exchange {
const maker = this.safeValue (group, 'ask_fee', {});
const taker = this.safeValue (group, 'bid_fee', {});
const marketId = this.safeString (group, 'market');
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- symbol = this.markets_by_id[marketId]['symbol'];
- }
+ const symbol = this.safeSymbol (marketId);
result[symbol] = {
'info': group,
'symbol': symbol,
@@ -77153,21 +90092,8 @@ module.exports = class oceanex extends Exchange {
// }
//
const status = this.parseOrderStatus (this.safeValue (order, 'state'));
- const marketId = this.safeValue2 (order, 'market', 'market_id');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const marketId = this.safeString2 (order, 'market', 'market_id');
+ const symbol = this.safeSymbol (marketId);
let timestamp = this.safeTimestamp (order, 'created_on');
if (timestamp === undefined) {
timestamp = this.parse8601 (this.safeString (order, 'created_at'));
@@ -77181,8 +90107,10 @@ module.exports = class oceanex extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': this.safeValue (order, 'ord_type'),
+ 'timeInForce': undefined,
'side': this.safeValue (order, 'side'),
'price': this.safeFloat (order, 'price'),
+ 'stopPrice': undefined,
'average': this.safeFloat (order, 'avg_price'),
'amount': this.safeFloat (order, 'volume'),
'remaining': this.safeFloat (order, 'remaining_volume'),
@@ -77289,7 +90217,7 @@ module.exports = class oceanex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],113:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],113:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -77307,7 +90235,7 @@ module.exports = class okcoin extends okex {
'hostname': 'okcoin.com',
'pro': true,
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27766791-89ffb502-5ee5-11e7-8a5b-c5950b68ac65.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295551-102fbf00-c50e-11ea-90a9-462eebba5829.jpg',
'www': 'https://www.okcoin.com',
'doc': 'https://www.okcoin.com/docs/en/',
'fees': 'https://www.okcoin.com/coin-fees',
@@ -77347,24 +90275,31 @@ module.exports = class okex extends Exchange {
'rateLimit': 1000, // up to 3000 requests per 5 minutes ≈ 600 requests per minute ≈ 10 requests per second ≈ 100 ms
'pro': true,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
'fetchCurrencies': false, // see below
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
- 'fetchTime': true,
- 'fetchTransactions': false,
- 'fetchMyTrades': true,
'fetchDepositAddress': true,
- 'fetchOrderTrades': true,
- 'fetchTickers': true,
+ 'fetchDeposits': true,
'fetchLedger': true,
- 'withdraw': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchOrderTrades': true,
+ 'fetchTime': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': false,
+ 'fetchWithdrawals': true,
'futures': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '60',
@@ -77379,6 +90314,10 @@ module.exports = class okex extends Exchange {
'12h': '43200',
'1d': '86400',
'1w': '604800',
+ '1M': '2678400',
+ '3M': '8035200',
+ '6M': '16070400',
+ '1y': '31536000',
},
'hostname': 'okex.com',
'urls': {
@@ -77439,6 +90378,7 @@ module.exports = class okex extends Exchange {
'instruments/{instrument_id}/ticker',
'instruments/{instrument_id}/trades',
'instruments/{instrument_id}/candles',
+ 'instruments/{instrument_id}/history/candles',
],
'post': [
'order_algo',
@@ -77503,6 +90443,7 @@ module.exports = class okex extends Exchange {
'instruments/{instrument_id}/ticker',
'instruments/{instrument_id}/trades',
'instruments/{instrument_id}/candles',
+ 'instruments/{instrument_id}/history/candles',
'instruments/{instrument_id}/index',
'rate',
'instruments/{instrument_id}/estimated_price',
@@ -77547,6 +90488,7 @@ module.exports = class okex extends Exchange {
'instruments/{instrument_id}/ticker',
'instruments/{instrument_id}/trades',
'instruments/{instrument_id}/candles',
+ 'instruments/{instrument_id}/history/candles',
'instruments/{instrument_id}/index',
'rate',
'instruments/{instrument_id}/open_interest',
@@ -77570,6 +90512,7 @@ module.exports = class okex extends Exchange {
'option': {
'get': [
'accounts',
+ 'position',
'{underlying}/position',
'accounts/{underlying}',
'orders/{underlying}',
@@ -77633,11 +90576,15 @@ module.exports = class okex extends Exchange {
// 401 Unauthorized — Invalid API Key
// 403 Forbidden — You do not have access to the requested resource
// 404 Not Found
+ // 429 Client Error: Too Many Requests for url
// 500 Internal Server Error — We had a problem with our server
'exact': {
'1': ExchangeError, // { "code": 1, "message": "System error" }
// undocumented
'failure to get a peer from the ring-balancer': ExchangeNotAvailable, // { "message": "failure to get a peer from the ring-balancer" }
+ 'Server is busy, please try again.': ExchangeNotAvailable, // { "message": "Server is busy, please try again." }
+ 'An unexpected error occurred': ExchangeError, // { "message": "An unexpected error occurred" }
+ 'System error': ExchangeError, // {"error_message":"System error","message":"System error"}
'4010': PermissionDenied, // { "code": 4010, "message": "For the security of your funds, withdrawals are not permitted within 24 hours after changing fund password / mobile number / Google Authenticator settings " }
// common
// '0': ExchangeError, // 200 successful,when the order placement / cancellation / operation is successful
@@ -77673,7 +90620,7 @@ module.exports = class okex extends Exchange {
'30027': AuthenticationError, // { "code": 30027, "message": "login failure" }
'30028': PermissionDenied, // { "code": 30028, "message": "unauthorized execution" }
'30029': AccountSuspended, // { "code": 30029, "message": "account suspended" }
- '30030': ExchangeError, // { "code": 30030, "message": "endpoint request failed. Please try again" }
+ '30030': ExchangeNotAvailable, // { "code": 30030, "message": "endpoint request failed. Please try again" }
'30031': BadRequest, // { "code": 30031, "message": "token does not exist" }
'30032': BadSymbol, // { "code": 30032, "message": "pair does not exist" }
'30033': BadRequest, // { "code": 30033, "message": "exchange domain does not exist" }
@@ -77683,6 +90630,7 @@ module.exports = class okex extends Exchange {
'30037': ExchangeNotAvailable, // { "code": 30037, "message": "endpoint is offline or unavailable" }
// '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" }
'30038': OnMaintenance, // {"client_oid":"","code":"30038","error_code":"30038","error_message":"Matching engine is being upgraded. Please try in about 1 minute.","message":"Matching engine is being upgraded. Please try in about 1 minute.","order_id":"-1","result":false}
+ '30044': RequestTimeout, // { "code":30044, "message":"Endpoint request timeout" }
// futures
'32001': AccountSuspended, // { "code": 32001, "message": "futures account suspended" }
'32002': PermissionDenied, // { "code": 32002, "message": "futures account does not exist" }
@@ -77763,7 +90711,7 @@ module.exports = class okex extends Exchange {
'33005': ExchangeError, // { "code": 33005, "message": "repayment amount must exceed 0" }
'33006': ExchangeError, // { "code": 33006, "message": "loan order not found" }
'33007': ExchangeError, // { "code": 33007, "message": "status not found" }
- '33008': ExchangeError, // { "code": 33008, "message": "loan amount cannot exceed the maximum limit" }
+ '33008': InsufficientFunds, // { "code": 33008, "message": "loan amount cannot exceed the maximum limit" }
'33009': ExchangeError, // { "code": 33009, "message": "user ID is blank" }
'33010': ExchangeError, // { "code": 33010, "message": "you cannot cancel an order during session 2 of call auction" }
'33011': ExchangeError, // { "code": 33011, "message": "no new market data" }
@@ -77809,6 +90757,7 @@ module.exports = class okex extends Exchange {
'33063': ExchangeError, // Leverage multiple is too low, there is insufficient margin in the account, please readjust the leverage ratio
'33064': ExchangeError, // The setting of the leverage ratio cannot be less than 2, please readjust the leverage ratio
'33065': ExchangeError, // Leverage ratio exceeds maximum leverage ratio, please readjust leverage ratio
+ '33085': InvalidOrder, // The value of the position and buying order has reached the position limit, and no further buying is allowed.
// account
'21009': ExchangeError, // Funds cannot be transferred out within 30 minutes after swap settlement(Funds cannot be transferred out within 30 minutes after swap settlement)
'34001': PermissionDenied, // { "code": 34001, "message": "withdrawal suspended" }
@@ -77854,10 +90803,10 @@ module.exports = class okex extends Exchange {
'35019': InvalidOrder, // { "code": 35019, "message": "Order size too large" }
'35020': InvalidOrder, // { "code": 35020, "message": "Order price too high" }
'35021': InvalidOrder, // { "code": 35021, "message": "Order size exceeded current tier limit" }
- '35022': ExchangeError, // { "code": 35022, "message": "Contract status error" }
- '35024': ExchangeError, // { "code": 35024, "message": "Contract not initialized" }
+ '35022': BadRequest, // { "code": 35022, "message": "Contract status error" }
+ '35024': BadRequest, // { "code": 35024, "message": "Contract not initialized" }
'35025': InsufficientFunds, // { "code": 35025, "message": "No account balance" }
- '35026': ExchangeError, // { "code": 35026, "message": "Contract settings not initialized" }
+ '35026': BadRequest, // { "code": 35026, "message": "Contract settings not initialized" }
'35029': OrderNotFound, // { "code": 35029, "message": "Order does not exist" }
'35030': InvalidOrder, // { "code": 35030, "message": "Order size too large" }
'35031': InvalidOrder, // { "code": 35031, "message": "Cancel order size too large" }
@@ -77964,6 +90913,9 @@ module.exports = class okex extends Exchange {
},
'precisionMode': TICK_SIZE,
'options': {
+ 'fetchOHLCV': {
+ 'type': 'Candles', // Candles or HistoryCandles
+ },
'createMarketBuyOrderRequiresPrice': true,
'fetchMarkets': [ 'spot', 'futures', 'swap', 'option' ],
'defaultType': 'spot', // 'account', 'spot', 'margin', 'futures', 'swap', 'option'
@@ -77978,6 +90930,7 @@ module.exports = class okex extends Exchange {
'commonCurrencies': {
// OKEX refers to ERC20 version of Aeternity (AEToken)
'AE': 'AET', // https://github.com/ccxt/ccxt/issues/4981
+ 'BOX': 'DefiBox',
'HOT': 'Hydro Protocol',
'HSR': 'HC',
'MAG': 'Maggie',
@@ -78284,7 +91237,7 @@ module.exports = class okex extends Exchange {
const name = this.safeString (currency, 'name');
const canDeposit = this.safeInteger (currency, 'can_deposit');
const canWithdraw = this.safeInteger (currency, 'can_withdraw');
- const active = canDeposit && canWithdraw;
+ const active = (canDeposit && canWithdraw) ? true : false;
result[code] = {
'id': id,
'code': code,
@@ -78436,7 +91389,7 @@ module.exports = class okex extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTickers (symbols = undefined, params = {}) {
@@ -78623,7 +91576,7 @@ module.exports = class okex extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// spot markets
//
@@ -78651,19 +91604,19 @@ module.exports = class okex extends Exchange {
if (Array.isArray (ohlcv)) {
const numElements = ohlcv.length;
const volumeIndex = (numElements > 6) ? 6 : 5;
- let timestamp = ohlcv[0];
+ let timestamp = this.safeValue (ohlcv, 0);
if (typeof timestamp === 'string') {
timestamp = this.parse8601 (timestamp);
}
return [
timestamp, // timestamp
- parseFloat (ohlcv[1]), // Open
- parseFloat (ohlcv[2]), // High
- parseFloat (ohlcv[3]), // Low
- parseFloat (ohlcv[4]), // Close
- // parseFloat (ohlcv[5]), // Quote Volume
- // parseFloat (ohlcv[6]), // Base Volume
- parseFloat (ohlcv[volumeIndex]), // Volume, okex will return base volume in the 7th element for future markets
+ this.safeFloat (ohlcv, 1), // Open
+ this.safeFloat (ohlcv, 2), // High
+ this.safeFloat (ohlcv, 3), // Low
+ this.safeFloat (ohlcv, 4), // Close
+ // this.safeFloat (ohlcv, 5), // Quote Volume
+ // this.safeFloat (ohlcv, 6), // Base Volume
+ this.safeFloat (ohlcv, volumeIndex), // Volume, okex will return base volume in the 7th element for future markets
];
} else {
return [
@@ -78680,59 +91633,92 @@ module.exports = class okex extends Exchange {
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
- const method = market['type'] + 'GetInstrumentsInstrumentIdCandles';
+ const duration = this.parseTimeframe (timeframe);
const request = {
'instrument_id': market['id'],
'granularity': this.timeframes[timeframe],
};
- const duration = this.parseTimeframe (timeframe);
- if (since !== undefined) {
- if (limit !== undefined) {
- request['end'] = this.iso8601 (this.sum (since, limit * duration * 1000));
+ const options = this.safeValue (this.options, 'fetchOHLCV', {});
+ const defaultType = this.safeString (options, 'type', 'Candles'); // Candles or HistoryCandles
+ const type = this.safeString (params, 'type', defaultType);
+ params = this.omit (params, 'type');
+ const method = market['type'] + 'GetInstrumentsInstrumentId' + type;
+ if (type === 'Candles') {
+ if (since !== undefined) {
+ if (limit !== undefined) {
+ request['end'] = this.iso8601 (this.sum (since, limit * duration * 1000));
+ }
+ request['start'] = this.iso8601 (since);
+ } else {
+ if (limit !== undefined) {
+ const now = this.milliseconds ();
+ request['start'] = this.iso8601 (now - limit * duration * 1000);
+ request['end'] = this.iso8601 (now);
+ }
}
- request['start'] = this.iso8601 (since);
- } else {
- const now = this.milliseconds ();
- if (limit !== undefined) {
- request['start'] = this.iso8601 (now - limit * duration * 1000);
- request['end'] = this.iso8601 (now);
+ } else if (type === 'HistoryCandles') {
+ if (market['option']) {
+ throw new NotSupported (this.id + ' fetchOHLCV does not have ' + type + ' for ' + market['type'] + ' markets');
+ }
+ if (since !== undefined) {
+ if (limit === undefined) {
+ limit = 300; // default
+ }
+ request['start'] = this.iso8601 (this.sum (since, limit * duration * 1000));
+ request['end'] = this.iso8601 (since);
+ } else {
+ if (limit !== undefined) {
+ const now = this.milliseconds ();
+ request['end'] = this.iso8601 (now - limit * duration * 1000);
+ request['start'] = this.iso8601 (now);
+ }
}
}
const response = await this[method] (this.extend (request, params));
//
// spot markets
//
- // [ { close: "0.02683401",
- // high: "0.02683401",
- // low: "0.02683401",
- // open: "0.02683401",
- // time: "2018-12-17T23:47:00.000Z",
- // volume: "0" },
- // ...
- // { close: "0.02684545",
- // high: "0.02685084",
- // low: "0.02683312",
- // open: "0.02683894",
- // time: "2018-12-17T20:28:00.000Z",
- // volume: "101.457222" } ]
+ // [
+ // {
+ // close: "0.02683401",
+ // high: "0.02683401",
+ // low: "0.02683401",
+ // open: "0.02683401",
+ // time: "2018-12-17T23:47:00.000Z",
+ // volume: "0"
+ // },
+ // {
+ // close: "0.02684545",
+ // high: "0.02685084",
+ // low: "0.02683312",
+ // open: "0.02683894",
+ // time: "2018-12-17T20:28:00.000Z",
+ // volume: "101.457222"
+ // }
+ // ]
//
// futures
//
- // [ [ 1545090660000,
- // 0.3171,
- // 0.3174,
- // 0.3171,
- // 0.3173,
- // 1648,
- // 51930.38579450868 ],
- // ...
- // [ 1545072720000,
- // 0.3159,
- // 0.3161,
- // 0.3144,
- // 0.3149,
- // 22886,
- // 725179.26172331 ] ]
+ // [
+ // [
+ // 1545090660000,
+ // 0.3171,
+ // 0.3174,
+ // 0.3171,
+ // 0.3173,
+ // 1648,
+ // 51930.38579450868
+ // ],
+ // [
+ // 1545072720000,
+ // 0.3159,
+ // 0.3161,
+ // 0.3144,
+ // 0.3149,
+ // 22886,
+ // 725179.26172331
+ // ]
+ // ]
//
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -78912,9 +91898,29 @@ module.exports = class okex extends Exchange {
const code = this.safeCurrencyCode (id);
const balance = this.safeValue (info, id, {});
const account = this.account ();
+ const totalAvailBalance = this.safeFloat (balance, 'total_avail_balance');
+ if (this.safeString (balance, 'margin_mode') === 'fixed') {
+ const contracts = this.safeValue (balance, 'contracts', []);
+ let free = totalAvailBalance;
+ for (let i = 0; i < contracts.length; i++) {
+ const contract = contracts[i];
+ const fixedBalance = this.safeFloat (contract, 'fixed_balance');
+ const realizedPnl = this.safeFloat (contract, 'realized_pnl');
+ const marginFrozen = this.safeFloat (contract, 'margin_frozen');
+ const marginForUnfilled = this.safeFloat (contract, 'margin_for_unfilled');
+ const margin = this.sum (fixedBalance, realizedPnl) - marginFrozen - marginForUnfilled;
+ free = this.sum (free, margin);
+ }
+ account['free'] = free;
+ } else {
+ const realizedPnl = this.safeFloat (balance, 'realized_pnl');
+ const unrealizedPnl = this.safeFloat (balance, 'unrealized_pnl');
+ const marginFrozen = this.safeFloat (balance, 'margin_frozen');
+ const marginForUnfilled = this.safeFloat (balance, 'margin_for_unfilled');
+ account['free'] = this.sum (totalAvailBalance, realizedPnl, unrealizedPnl) - marginFrozen - marginForUnfilled;
+ }
// it may be incorrect to use total, free and used for swap accounts
account['total'] = this.safeFloat (balance, 'equity');
- account['free'] = this.safeFloat (balance, 'total_avail_balance');
result[code] = account;
}
return this.parseBalance (result);
@@ -79117,17 +92123,29 @@ module.exports = class okex extends Exchange {
let request = {
'instrument_id': market['id'],
// 'client_oid': 'abcdef1234567890', // [a-z0-9]{1,32}
- // 'order_type': '0', // 0: Normal limit order (Unfilled and 0 represent normal limit order) 1: Post only 2: Fill Or Kill 3: Immediatel Or Cancel
+ // 'order_type': '0', // 0 = Normal limit order, 1 = Post only, 2 = Fill Or Kill, 3 = Immediatel Or Cancel, 4 = Market for futures only
};
+ const clientOrderId = this.safeString2 (params, 'client_oid', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['client_oid'] = clientOrderId;
+ params = this.omit (params, [ 'client_oid', 'clientOrderId' ]);
+ }
let method = undefined;
if (market['futures'] || market['swap']) {
const size = market['futures'] ? this.numberToString (amount) : this.amountToPrecision (symbol, amount);
request = this.extend (request, {
'type': type, // 1:open long 2:open short 3:close long 4:close short for futures
'size': size,
- 'price': this.priceToPrecision (symbol, price),
// 'match_price': '0', // Order at best counter party price? (0:no 1:yes). The default is 0. If it is set as 1, the price parameter will be ignored. When posting orders at best bid price, order_type can only be 0 (regular order).
});
+ const orderType = this.safeString (params, 'order_type');
+ // order_type === '4' means a market order
+ const isMarketOrder = (type === 'market') || (orderType === '4');
+ if (isMarketOrder) {
+ request['order_type'] = '4';
+ } else {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
if (market['futures']) {
request['leverage'] = '10'; // or '20'
}
@@ -79176,7 +92194,11 @@ module.exports = class okex extends Exchange {
// "result":true
// }
//
- return this.parseOrder (response, market);
+ const order = this.parseOrder (response, market);
+ return this.extend (order, {
+ 'type': type,
+ 'side': side,
+ });
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -79185,7 +92207,16 @@ module.exports = class okex extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
- const type = market['type'];
+ let type = undefined;
+ if (market['futures'] || market['swap']) {
+ type = market['type'];
+ } else {
+ const defaultType = this.safeString2 (this.options, 'cancelOrder', 'defaultType', market['type']);
+ type = this.safeString (params, 'type', defaultType);
+ }
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " cancelOrder requires a type parameter (one of 'spot', 'margin', 'futures', 'swap').");
+ }
let method = type + 'PostCancelOrder';
const request = {
'instrument_id': market['id'],
@@ -79195,15 +92226,15 @@ module.exports = class okex extends Exchange {
} else {
method += 's';
}
- const clientOid = this.safeString (params, 'client_oid');
- if (clientOid !== undefined) {
+ const clientOrderId = this.safeString2 (params, 'client_oid', 'clientOrderId');
+ if (clientOrderId !== undefined) {
method += 'ClientOid';
- request['client_oid'] = clientOid;
+ request['client_oid'] = clientOrderId;
} else {
method += 'OrderId';
request['order_id'] = id;
}
- const query = this.omit (params, 'type');
+ const query = this.omit (params, [ 'type', 'client_oid', 'clientOrderId' ]);
const response = await this[method] (this.extend (request, query));
const result = ('result' in response) ? response : this.safeValue (response, market['id'], {});
//
@@ -79325,17 +92356,10 @@ module.exports = class okex extends Exchange {
const id = this.safeString (order, 'order_id');
const timestamp = this.parse8601 (this.safeString (order, 'timestamp'));
let side = this.safeString (order, 'side');
- let type = this.safeString (order, 'type');
+ const type = this.safeString (order, 'type');
if ((side !== 'buy') && (side !== 'sell')) {
side = this.parseOrderSide (type);
}
- if ((type !== 'limit') && (type !== 'market')) {
- if ('pnl' in order) {
- type = 'futures';
- } else {
- type = 'swap';
- }
- }
let symbol = undefined;
const marketId = this.safeString (order, 'instrument_id');
if (marketId in this.markets_by_id) {
@@ -79383,7 +92407,11 @@ module.exports = class okex extends Exchange {
'currency': feeCurrency,
};
}
- const clientOrderId = this.safeString (order, 'client_oid');
+ let clientOrderId = this.safeString (order, 'client_oid');
+ if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
+ clientOrderId = undefined; // fix empty clientOrderId string
+ }
+ const stopPrice = this.safeFloat (order, 'trigger_price');
return {
'info': order,
'id': id,
@@ -79393,8 +92421,10 @@ module.exports = class okex extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'average': average,
'cost': cost,
'amount': amount,
@@ -79487,7 +92517,16 @@ module.exports = class okex extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
- const type = market['type'];
+ let type = undefined;
+ if (market['futures'] || market['swap']) {
+ type = market['type'];
+ } else {
+ const defaultType = this.safeString2 (this.options, 'fetchOrder', 'defaultType', market['type']);
+ type = this.safeString (params, 'type', defaultType);
+ }
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " fetchOrder requires a type parameter (one of 'spot', 'margin', 'futures', 'swap').");
+ }
const request = {
'instrument_id': market['id'],
// '-2': failed,
@@ -79568,7 +92607,7 @@ module.exports = class okex extends Exchange {
// }
//
let orders = undefined;
- if (market['type'] === 'swap' || market['type'] === 'futures') {
+ if (market['swap'] || market['futures']) {
orders = this.safeValue (response, 'order_info', []);
} else {
orders = response;
@@ -79724,7 +92763,7 @@ module.exports = class okex extends Exchange {
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
- request['code'] = currency['code'];
+ request['currency'] = currency['id'];
method += 'Currency';
}
const response = await this[method] (this.extend (request, params));
@@ -79738,7 +92777,7 @@ module.exports = class okex extends Exchange {
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
- request['code'] = currency['code'];
+ request['currency'] = currency['id'];
method += 'Currency';
}
const response = await this[method] (this.extend (request, params));
@@ -79771,7 +92810,7 @@ module.exports = class okex extends Exchange {
//
const statuses = {
'-3': 'pending',
- '-2': 'pending',
+ '-2': 'canceled',
'-1': 'failed',
'0': 'pending',
'1': 'pending',
@@ -79811,12 +92850,14 @@ module.exports = class okex extends Exchange {
// fetchDeposits
//
// {
- // amount: "0.47847546",
- // txid: "1723573_3_0_0_WALLET",
- // currency: "BTC",
- // to: "",
- // timestamp: "2018-08-16T03:41:10.000Z",
- // status: "2"
+ // "amount": "4.19511659",
+ // "txid": "14c9a8c925647cdb7e5b2937ea9aefe2b29b2c273150ad3f44b3b8a4635ed437",
+ // "currency": "XMR",
+ // "from": "",
+ // "to": "48PjH3ksv1fiXniKvKvyH5UtFs5WhfS2Vf7U3TwzdRJtCc7HJWvCQe56dRahyhQyTAViXZ8Nzk4gQg6o4BJBMUoxNy8y8g7",
+ // "deposit_id": 11571659, <-- we can use this
+ // "timestamp": "2019-10-01T14:54:19.000Z",
+ // "status": "2"
// }
//
let type = undefined;
@@ -79831,7 +92872,7 @@ module.exports = class okex extends Exchange {
address = addressTo;
} else {
// the payment_id will appear on new deposits but appears to be removed from the response after 2 months
- id = this.safeString (transaction, 'payment_id');
+ id = this.safeString2 (transaction, 'payment_id', 'deposit_id');
type = 'deposit';
address = addressTo;
}
@@ -79882,49 +92923,74 @@ module.exports = class okex extends Exchange {
parseMyTrade (pair, market = undefined) {
// check that trading symbols match in both entries
- const first = pair[0];
- const second = pair[1];
- const firstMarketId = this.safeString (first, 'instrument_id');
- const secondMarketId = this.safeString (second, 'instrument_id');
+ const userTrade = this.safeValue (pair, 1);
+ const otherTrade = this.safeValue (pair, 0);
+ const firstMarketId = this.safeString (otherTrade, 'instrument_id');
+ const secondMarketId = this.safeString (userTrade, 'instrument_id');
if (firstMarketId !== secondMarketId) {
throw new NotSupported (this.id + ' parseMyTrade() received unrecognized response format, differing instrument_ids in one fill, the exchange API might have changed, paste your verbose output: https://github.com/ccxt/ccxt/wiki/FAQ#what-is-required-to-get-help');
}
const marketId = firstMarketId;
- // determine the base and quote
- let quoteId = undefined;
- let symbol = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- quoteId = market['quoteId'];
- symbol = market['symbol'];
- } else {
- const parts = marketId.split ('-');
- quoteId = this.safeString (parts, 1);
- symbol = marketId;
- }
- const id = this.safeString (first, 'trade_id');
- const price = this.safeFloat (first, 'price');
- // determine buy/sell side and amounts
- // get the side from either the first trade or the second trade
- let feeCost = this.safeFloat (first, 'fee');
- const index = (feeCost !== 0) ? 0 : 1;
- const userTrade = this.safeValue (pair, index);
- const otherTrade = this.safeValue (pair, 1 - index);
- const receivedCurrencyId = this.safeString (userTrade, 'currency');
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
+ const quoteId = market['quoteId'];
let side = undefined;
let amount = undefined;
let cost = undefined;
+ const receivedCurrencyId = this.safeString (userTrade, 'currency');
+ let feeCurrencyId = undefined;
if (receivedCurrencyId === quoteId) {
- side = 'sell';
+ side = this.safeString (otherTrade, 'side');
amount = this.safeFloat (otherTrade, 'size');
cost = this.safeFloat (userTrade, 'size');
+ feeCurrencyId = this.safeString (otherTrade, 'currency');
} else {
- side = 'buy';
+ side = this.safeString (userTrade, 'side');
amount = this.safeFloat (userTrade, 'size');
cost = this.safeFloat (otherTrade, 'size');
+ feeCurrencyId = this.safeString (userTrade, 'currency');
+ }
+ const id = this.safeString (userTrade, 'trade_id');
+ const price = this.safeFloat (userTrade, 'price');
+ const feeCostFirst = this.safeFloat (otherTrade, 'fee');
+ const feeCostSecond = this.safeFloat (userTrade, 'fee');
+ const feeCurrencyCodeFirst = this.safeCurrencyCode (this.safeString (otherTrade, 'currency'));
+ const feeCurrencyCodeSecond = this.safeCurrencyCode (this.safeString (userTrade, 'currency'));
+ let fee = undefined;
+ let fees = undefined;
+ // fee is either a positive number (invitation rebate)
+ // or a negative number (transaction fee deduction)
+ // therefore we need to invert the fee
+ // more about it https://github.com/ccxt/ccxt/issues/5909
+ if ((feeCostFirst !== undefined) && (feeCostFirst !== 0)) {
+ if ((feeCostSecond !== undefined) && (feeCostSecond !== 0)) {
+ fees = [
+ {
+ 'cost': -feeCostFirst,
+ 'currency': feeCurrencyCodeFirst,
+ },
+ {
+ 'cost': -feeCostSecond,
+ 'currency': feeCurrencyCodeSecond,
+ },
+ ];
+ } else {
+ fee = {
+ 'cost': -feeCostFirst,
+ 'currency': feeCurrencyCodeFirst,
+ };
+ }
+ } else if ((feeCostSecond !== undefined) && (feeCostSecond !== 0)) {
+ fee = {
+ 'cost': -feeCostSecond,
+ 'currency': feeCurrencyCodeSecond,
+ };
+ } else {
+ fee = {
+ 'cost': 0,
+ 'currency': this.safeCurrencyCode (feeCurrencyId),
+ };
}
- feeCost = (feeCost !== 0) ? feeCost : this.safeFloat (second, 'fee');
- const trade = this.safeValue (pair, index);
//
// simplified structures to show the underlying semantics
//
@@ -79958,28 +93024,15 @@ module.exports = class okex extends Exchange {
// "size":"31.03998952", // ←-- cost
// }
//
- const timestamp = this.parse8601 (this.safeString2 (trade, 'timestamp', 'created_at'));
- let takerOrMaker = this.safeString2 (trade, 'exec_type', 'liquidity');
+ const timestamp = this.parse8601 (this.safeString2 (userTrade, 'timestamp', 'created_at'));
+ let takerOrMaker = this.safeString2 (userTrade, 'exec_type', 'liquidity');
if (takerOrMaker === 'M') {
takerOrMaker = 'maker';
} else if (takerOrMaker === 'T') {
takerOrMaker = 'taker';
}
- let fee = undefined;
- if (feeCost !== undefined) {
- const feeCurrencyId = this.safeString (userTrade, 'currency');
- const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
- fee = {
- // fee is either a positive number (invitation rebate)
- // or a negative number (transaction fee deduction)
- // therefore we need to invert the fee
- // more about it https://github.com/ccxt/ccxt/issues/5909
- 'cost': -feeCost,
- 'currency': feeCurrencyCode,
- };
- }
- const orderId = this.safeString (trade, 'order_id');
- return {
+ const orderId = this.safeString (userTrade, 'order_id');
+ const result = {
'info': pair,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
@@ -79994,6 +93047,10 @@ module.exports = class okex extends Exchange {
'cost': cost,
'fee': fee,
};
+ if (fees !== undefined) {
+ result['fees'] = fees;
+ }
+ return result;
}
parseMyTrades (trades, market = undefined, since = undefined, limit = undefined, params = {}) {
@@ -80033,8 +93090,8 @@ module.exports = class okex extends Exchange {
const request = {
'instrument_id': market['id'],
// 'order_id': id, // string
- // 'after': '1', // return the page after the specified page number
- // 'before': '1', // return the page before the specified page number
+ // 'after': '1', // pagination of data to return records earlier than the requested ledger_id
+ // 'before': '1', // P=pagination of data to return records newer than the requested ledger_id
// 'limit': limit, // optional, number of results per request, default = maximum = 100
};
const defaultType = this.safeString2 (this.options, 'fetchMyTrades', 'defaultType');
@@ -80126,6 +93183,277 @@ module.exports = class okex extends Exchange {
return await this.fetchMyTrades (symbol, since, limit, this.extend (request, params));
}
+ async fetchPosition (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ let method = undefined;
+ const request = {
+ 'instrument_id': market['id'],
+ // 'order_id': id, // string
+ // 'after': '1', // pagination of data to return records earlier than the requested ledger_id
+ // 'before': '1', // P=pagination of data to return records newer than the requested ledger_id
+ // 'limit': limit, // optional, number of results per request, default = maximum = 100
+ };
+ const type = market['type'];
+ if ((type === 'futures') || (type === 'swap')) {
+ method = type + 'GetInstrumentIdPosition';
+ } else if (type === 'option') {
+ const underlying = this.safeString (params, 'underlying');
+ if (underlying === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchPosition() requires an underlying parameter for ' + type + ' market ' + symbol);
+ }
+ method = type + 'GetUnderlyingPosition';
+ } else {
+ throw new NotSupported (this.id + ' fetchPosition() does not support ' + type + ' market ' + symbol + ', supported market types are futures, swap or option');
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // futures
+ //
+ // crossed margin mode
+ //
+ // {
+ // "result": true,
+ // "holding": [
+ // {
+ // "long_qty": "2",
+ // "long_avail_qty": "2",
+ // "long_avg_cost": "8260",
+ // "long_settlement_price": "8260",
+ // "realised_pnl": "0.00020928",
+ // "short_qty": "2",
+ // "short_avail_qty": "2",
+ // "short_avg_cost": "8259.99",
+ // "short_settlement_price": "8259.99",
+ // "liquidation_price": "113.81",
+ // "instrument_id": "BTC-USD-191227",
+ // "leverage": "10",
+ // "created_at": "2019-09-25T07:58:42.129Z",
+ // "updated_at": "2019-10-08T14:02:51.029Z",
+ // "margin_mode": "crossed",
+ // "short_margin": "0.00242197",
+ // "short_pnl": "6.63E-6",
+ // "short_pnl_ratio": "0.002477997",
+ // "short_unrealised_pnl": "6.63E-6",
+ // "long_margin": "0.00242197",
+ // "long_pnl": "-6.65E-6",
+ // "long_pnl_ratio": "-0.002478",
+ // "long_unrealised_pnl": "-6.65E-6",
+ // "long_settled_pnl": "0",
+ // "short_settled_pnl": "0",
+ // "last": "8257.57"
+ // }
+ // ],
+ // "margin_mode": "crossed"
+ // }
+ //
+ // fixed margin mode
+ //
+ // {
+ // "result": true,
+ // "holding": [
+ // {
+ // "long_qty": "4",
+ // "long_avail_qty": "4",
+ // "long_margin": "0.00323844",
+ // "long_liqui_price": "7762.09",
+ // "long_pnl_ratio": "0.06052306",
+ // "long_avg_cost": "8234.43",
+ // "long_settlement_price": "8234.43",
+ // "realised_pnl": "-0.00000296",
+ // "short_qty": "2",
+ // "short_avail_qty": "2",
+ // "short_margin": "0.00241105",
+ // "short_liqui_price": "9166.74",
+ // "short_pnl_ratio": "0.03318052",
+ // "short_avg_cost": "8295.13",
+ // "short_settlement_price": "8295.13",
+ // "instrument_id": "BTC-USD-191227",
+ // "long_leverage": "15",
+ // "short_leverage": "10",
+ // "created_at": "2019-09-25T07:58:42.129Z",
+ // "updated_at": "2019-10-08T13:12:09.438Z",
+ // "margin_mode": "fixed",
+ // "short_margin_ratio": "0.10292507",
+ // "short_maint_margin_ratio": "0.005",
+ // "short_pnl": "7.853E-5",
+ // "short_unrealised_pnl": "7.853E-5",
+ // "long_margin_ratio": "0.07103743",
+ // "long_maint_margin_ratio": "0.005",
+ // "long_pnl": "1.9841E-4",
+ // "long_unrealised_pnl": "1.9841E-4",
+ // "long_settled_pnl": "0",
+ // "short_settled_pnl": "0",
+ // "last": "8266.99"
+ // }
+ // ],
+ // "margin_mode": "fixed"
+ // }
+ //
+ // swap
+ //
+ // crossed margin mode
+ //
+ // {
+ // "margin_mode": "crossed",
+ // "timestamp": "2019-09-27T03:49:02.018Z",
+ // "holding": [
+ // {
+ // "avail_position": "3",
+ // "avg_cost": "59.49",
+ // "instrument_id": "LTC-USD-SWAP",
+ // "last": "55.98",
+ // "leverage": "10.00",
+ // "liquidation_price": "4.37",
+ // "maint_margin_ratio": "0.0100",
+ // "margin": "0.0536",
+ // "position": "3",
+ // "realized_pnl": "0.0000",
+ // "unrealized_pnl": "0",
+ // "settled_pnl": "-0.0330",
+ // "settlement_price": "55.84",
+ // "side": "long",
+ // "timestamp": "2019-09-27T03:49:02.018Z"
+ // },
+ // ]
+ // }
+ //
+ // fixed margin mode
+ //
+ // {
+ // "margin_mode": "fixed",
+ // "timestamp": "2019-09-27T03:47:37.230Z",
+ // "holding": [
+ // {
+ // "avail_position": "20",
+ // "avg_cost": "8025.0",
+ // "instrument_id": "BTC-USD-SWAP",
+ // "last": "8113.1",
+ // "leverage": "15.00",
+ // "liquidation_price": "7002.6",
+ // "maint_margin_ratio": "0.0050",
+ // "margin": "0.0454",
+ // "position": "20",
+ // "realized_pnl": "-0.0001",
+ // "unrealized_pnl": "0",
+ // "settled_pnl": "0.0076",
+ // "settlement_price": "8279.2",
+ // "side": "long",
+ // "timestamp": "2019-09-27T03:47:37.230Z"
+ // }
+ // ]
+ // }
+ //
+ // option
+ //
+ // {
+ // "holding":[
+ // {
+ // "instrument_id":"BTC-USD-190927-12500-C",
+ // "position":"20",
+ // "avg_cost":"3.26",
+ // "avail_position":"20",
+ // "settlement_price":"0.017",
+ // "total_pnl":"50",
+ // "pnl_ratio":"0.3",
+ // "realized_pnl":"40",
+ // "unrealized_pnl":"10",
+ // "pos_margin":"100",
+ // "option_value":"70",
+ // "created_at":"2019-08-30T03:09:20.315Z",
+ // "updated_at":"2019-08-30T03:40:18.318Z"
+ // },
+ // {
+ // "instrument_id":"BTC-USD-190927-12500-P",
+ // "position":"20",
+ // "avg_cost":"3.26",
+ // "avail_position":"20",
+ // "settlement_price":"0.019",
+ // "total_pnl":"50",
+ // "pnl_ratio":"0.3",
+ // "realized_pnl":"40",
+ // "unrealized_pnl":"10",
+ // "pos_margin":"100",
+ // "option_value":"70",
+ // "created_at":"2019-08-30T03:09:20.315Z",
+ // "updated_at":"2019-08-30T03:40:18.318Z"
+ // }
+ // ]
+ // }
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let method = undefined;
+ const defaultType = this.safeString2 (this.options, 'fetchPositions', 'defaultType');
+ const type = this.safeString (params, 'type', defaultType);
+ if ((type === 'futures') || (type === 'swap')) {
+ method = type + 'GetPosition';
+ } else if (type === 'option') {
+ const underlying = this.safeString (params, 'underlying');
+ if (underlying === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchPositions() requires an underlying parameter for ' + type + ' markets');
+ }
+ method = type + 'GetUnderlyingPosition';
+ } else {
+ throw new NotSupported (this.id + ' fetchPositions() does not support ' + type + ' markets, supported market types are futures, swap or option');
+ }
+ params = this.omit (params, 'type');
+ const response = await this[method] (params);
+ //
+ // futures
+ //
+ // ...
+ //
+ //
+ // swap
+ //
+ // ...
+ //
+ // option
+ //
+ // {
+ // "holding":[
+ // {
+ // "instrument_id":"BTC-USD-190927-12500-C",
+ // "position":"20",
+ // "avg_cost":"3.26",
+ // "avail_position":"20",
+ // "settlement_price":"0.017",
+ // "total_pnl":"50",
+ // "pnl_ratio":"0.3",
+ // "realized_pnl":"40",
+ // "unrealized_pnl":"10",
+ // "pos_margin":"100",
+ // "option_value":"70",
+ // "created_at":"2019-08-30T03:09:20.315Z",
+ // "updated_at":"2019-08-30T03:40:18.318Z"
+ // },
+ // {
+ // "instrument_id":"BTC-USD-190927-12500-P",
+ // "position":"20",
+ // "avg_cost":"3.26",
+ // "avail_position":"20",
+ // "settlement_price":"0.019",
+ // "total_pnl":"50",
+ // "pnl_ratio":"0.3",
+ // "realized_pnl":"40",
+ // "unrealized_pnl":"10",
+ // "pos_margin":"100",
+ // "option_value":"70",
+ // "created_at":"2019-08-30T03:09:20.315Z",
+ // "updated_at":"2019-08-30T03:40:18.318Z"
+ // }
+ // ]
+ // }
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const defaultType = this.safeString2 (this.options, 'fetchLedger', 'defaultType');
@@ -80316,9 +93644,17 @@ module.exports = class okex extends Exchange {
// },
// ]
//
+ const responseLength = response.length;
+ if (responseLength < 1) {
+ return [];
+ }
const isArray = Array.isArray (response[0]);
const isMargin = (type === 'margin');
const entries = (isMargin && isArray) ? response[0] : response;
+ if (type === 'swap') {
+ const ledgerEntries = this.parseLedger (entries);
+ return this.filterBySymbolSinceLimit (ledgerEntries, code, since, limit);
+ }
return this.parseLedger (entries, currency, since, limit);
}
@@ -80428,6 +93764,12 @@ module.exports = class okex extends Exchange {
const before = undefined;
const after = this.safeFloat (item, 'balance');
const status = 'ok';
+ const marketId = this.safeString (item, 'instrument_id');
+ let symbol = undefined;
+ if (marketId in this.markets_by_id) {
+ const market = this.markets_by_id[marketId];
+ symbol = market['symbol'];
+ }
return {
'info': item,
'id': id,
@@ -80436,6 +93778,7 @@ module.exports = class okex extends Exchange {
'referenceAccount': referenceAccount,
'type': type,
'currency': code,
+ 'symbol': symbol,
'amount': amount,
'before': before, // balance before
'after': after, // balance after
@@ -80483,7 +93826,7 @@ module.exports = class okex extends Exchange {
headers['Content-Type'] = 'application/json';
}
const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256', 'base64');
- headers['OK-ACCESS-SIGN'] = this.decode (signature);
+ headers['OK-ACCESS-SIGN'] = signature;
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
@@ -80501,30 +93844,35 @@ module.exports = class okex extends Exchange {
}
handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (!response) {
+ return; // fallback to default error handler
+ }
const feedback = this.id + ' ' + body;
if (code === 503) {
// {"message":"name resolution failed"}
throw new ExchangeNotAvailable (feedback);
}
- if (!response) {
- return; // fallback to default error handler
- }
+ //
+ // {"error_message":"Order does not exist","result":"true","error_code":"35029","order_id":"-1"}
+ //
const message = this.safeString (response, 'message');
const errorCode = this.safeString2 (response, 'code', 'error_code');
- if (message !== undefined) {
+ const nonEmptyMessage = ((message !== undefined) && (message !== ''));
+ const nonZeroErrorCode = (errorCode !== undefined) && (errorCode !== '0');
+ if (nonEmptyMessage) {
this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ }
+ if (nonZeroErrorCode) {
this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
- const nonEmptyMessage = (message !== '');
- const nonZeroErrorCode = (errorCode !== undefined) && (errorCode !== '0');
- if (nonZeroErrorCode || nonEmptyMessage) {
- throw new ExchangeError (feedback); // unknown message
- }
+ }
+ if (nonZeroErrorCode || nonEmptyMessage) {
+ throw new ExchangeError (feedback); // unknown message
}
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],115:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],115:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -80544,9 +93892,15 @@ module.exports = class paymium extends Exchange {
'version': 'v1',
'has': {
'CORS': true,
+ 'fetchBalance': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'fetchOrderBook': true,
+ 'createOrder': true,
+ 'cancelOrder': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27790564-a945a9d4-5ff9-11e7-9d2d-b635763f2f24.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87153930-f0f02200-c2c0-11ea-9c0a-40337375ae89.jpg',
'api': 'https://paymium.com/api',
'www': 'https://www.paymium.com',
'fees': 'https://www.paymium.com/page/help/fees',
@@ -80560,31 +93914,34 @@ module.exports = class paymium extends Exchange {
'public': {
'get': [
'countries',
- 'data/{id}/ticker',
- 'data/{id}/trades',
- 'data/{id}/depth',
+ 'data/{currency}/ticker',
+ 'data/{currency}/trades',
+ 'data/{currency}/depth',
'bitcoin_charts/{id}/trades',
'bitcoin_charts/{id}/depth',
],
},
'private': {
'get': [
- 'merchant/get_payment/{uuid}',
'user',
'user/addresses',
- 'user/addresses/{btc_address}',
+ 'user/addresses/{address}',
'user/orders',
'user/orders/{uuid}',
'user/price_alerts',
+ 'merchant/get_payment/{uuid}',
],
'post': [
- 'user/orders',
'user/addresses',
+ 'user/orders',
+ 'user/withdrawals',
+ 'user/email_transfers',
'user/payment_requests',
'user/price_alerts',
'merchant/create_payment',
],
'delete': [
+ 'user/orders/{uuid}',
'user/orders/{uuid}/cancel',
'user/price_alerts/{id}',
],
@@ -80625,17 +93982,18 @@ module.exports = class paymium extends Exchange {
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {
- 'id': this.marketId (symbol),
+ 'currency': this.marketId (symbol),
};
- const response = await this.publicGetDataIdDepth (this.extend (request, params));
+ const response = await this.publicGetDataCurrencyDepth (this.extend (request, params));
return this.parseOrderBook (response, undefined, 'bids', 'asks', 'price', 'amount');
}
async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
const request = {
- 'id': this.marketId (symbol),
+ 'currency': this.marketId (symbol),
};
- const ticker = await this.publicGetDataIdTicker (this.extend (request, params));
+ const ticker = await this.publicGetDataCurrencyTicker (this.extend (request, params));
const timestamp = this.safeTimestamp (ticker, 'at');
const vwap = this.safeFloat (ticker, 'vwap');
const baseVolume = this.safeFloat (ticker, 'volume');
@@ -80706,9 +94064,9 @@ module.exports = class paymium extends Exchange {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
- 'id': market['id'],
+ 'currency': market['id'],
};
- const response = await this.publicGetDataIdTrades (this.extend (request, params));
+ const response = await this.publicGetDataCurrencyTrades (this.extend (request, params));
return this.parseTrades (response, market, since, limit);
}
@@ -80779,13 +94137,2520 @@ module.exports = class paymium extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],116:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],116:[function(require,module,exports){
+'use strict';
+
+// ----------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, BadSymbol, AuthenticationError, InsufficientFunds, InvalidOrder, ArgumentsRequired, OrderNotFound, BadRequest, PermissionDenied, AccountSuspended, CancelPending, DDoSProtection, DuplicateOrderId, NotSupported } = require ('./base/errors');
+const { TICK_SIZE, ROUND, DECIMAL_PLACES } = require ('./base/functions/number');
+
+// ----------------------------------------------------------------------------
+
+module.exports = class phemex extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'phemex',
+ 'name': 'Phemex',
+ 'countries': [ 'CN' ], // China
+ 'rateLimit': 100,
+ 'version': 'v1',
+ 'certified': false,
+ 'pro': true,
+ 'has': {
+ 'cancelAllOrders': true, // swap contracts only
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/85225056-221eb600-b3d7-11ea-930d-564d2690e3f6.jpg',
+ 'test': {
+ 'v1': 'https://testnet-api.phemex.com/v1',
+ 'public': 'https://testnet-api.phemex.com/exchange/public',
+ 'private': 'https://testnet-api.phemex.com',
+ },
+ 'api': {
+ 'v1': 'https://api.phemex.com/v1',
+ 'public': 'https://api.phemex.com/exchange/public',
+ 'private': 'https://api.phemex.com',
+ },
+ 'www': 'https://phemex.com',
+ 'doc': 'https://github.com/phemex/phemex-api-docs',
+ 'fees': 'https://phemex.com/fees-conditions',
+ 'referral': 'https://phemex.com/register?referralCode=EDNVJ',
+ },
+ 'timeframes': {
+ '1m': '60',
+ '3m': '180',
+ '5m': '300',
+ '15m': '900',
+ '30m': '1800',
+ '1h': '3600',
+ '2h': '7200',
+ '3h': '10800',
+ '4h': '14400',
+ '6h': '21600',
+ '12h': '43200',
+ '1d': '86400',
+ '1w': '604800',
+ '1M': '2592000',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'cfg/v2/products', // spot + contracts
+ 'products', // contracts only
+ 'nomics/trades', // ?market=&since=
+ 'md/kline', // ?from=1589811875&resolution=1800&symbol=sBTCUSDT&to=1592457935
+ ],
+ },
+ 'v1': {
+ 'get': [
+ 'md/orderbook', // ?symbol=&id=
+ 'md/trade', // ?symbol=&id=
+ 'md/ticker/24hr', // ?symbol=&id=
+ 'md/ticker/24hr/all', // ?id=
+ 'md/spot/ticker/24hr', // ?symbol=&id=
+ 'md/spot/ticker/24hr/all', // ?symbol=&id=
+ 'exchange/public/products', // contracts only
+ ],
+ },
+ 'private': {
+ 'get': [
+ // spot
+ 'spot/orders/active', // ?symbol=&orderID=
+ // 'spot/orders/active', // ?symbol=&clOrDID=
+ 'spot/orders', // ?symbol=
+ 'spot/wallets', // ?currency=
+ 'exchange/spot/order', // ?symbol=&ordStatus=ordType=&start=&end=&limit=&offset=
+ 'exchange/spot/order/trades', // ?symbol=&start=&end=&limit=&offset=
+ // swap
+ 'accounts/accountPositions', // ?currency=
+ 'orders/activeList', // ?symbol=
+ 'exchange/order/list', // ?symbol=&start=&end=&offset=&limit=&ordStatus=&withCount=
+ 'exchange/order', // ?symbol=&orderID=
+ // 'exchange/order', // ?symbol=&clOrdID=
+ 'exchange/order/trade', // ?symbol=&start=&end=&limit=&offset=&withCount=
+ 'phemex-user/users/children', // ?offset=&limit=&withCount=
+ 'phemex-user/wallets/v2/depositAddress', // ?_t=1592722635531¤cy=USDT
+ 'exchange/margins/transfer', // ?start=&end=&offset=&limit=&withCount=
+ 'exchange/wallets/confirm/withdraw', // ?code=
+ 'exchange/wallets/withdrawList', // ?currency=&limit=&offset=&withCount=
+ 'exchange/wallets/depositList', // ?currency=&offset=&limit=
+ 'exchange/wallets/v2/depositAddress', // ?currency=
+ ],
+ 'post': [
+ // spot
+ 'spot/orders',
+ // swap
+ 'orders',
+ 'positions/assign', // ?symbol=&posBalance=&posBalanceEv=
+ 'exchange/wallets/transferOut',
+ 'exchange/wallets/transferIn',
+ 'exchange/margins',
+ 'exchange/wallets/createWithdraw', // ?otpCode=
+ 'exchange/wallets/cancelWithdraw',
+ 'exchange/wallets/createWithdrawAddress', // ?otpCode={optCode}
+ ],
+ 'put': [
+ // spot
+ 'spot/orders', // ?symbol=&orderID=&origClOrdID=&clOrdID=&priceEp=&baseQtyEV="eQtyEv=&stopPxEp=
+ // swap
+ 'orders/replace', // ?symbol=&orderID=&origClOrdID=&clOrdID=&price=&priceEp=&orderQty=&stopPx=&stopPxEp=&takeProfit=&takeProfitEp=&stopLoss=&stopLossEp=&pegOffsetValueEp=&pegPriceType=
+ 'positions/leverage', // ?symbol=&leverage=&leverageEr=
+ 'positions/riskLimit', // ?symbol=&riskLimit=&riskLimitEv=
+ ],
+ 'delete': [
+ // spot
+ 'spot/orders', // ?symbol=&orderID=
+ // 'spot/orders', // ?symbol=&clOrdID=
+ // swap
+ 'orders/cancel', // ?symbol=&orderID=
+ 'orders', // ?symbol=&orderID=,,
+ 'orders/all', // ?symbol=&untriggered=&text=
+ ],
+ },
+ },
+ 'precisionMode': TICK_SIZE,
+ 'fees': {
+ 'trading': {
+ 'tierBased': false,
+ 'percentage': true,
+ 'taker': 0.1 / 100,
+ 'maker': 0.1 / 100,
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ },
+ 'exceptions': {
+ 'exact': {
+ // not documented
+ '412': BadRequest, // {"code":412,"msg":"Missing parameter - resolution","data":null}
+ '6001': BadRequest, // {"error":{"code":6001,"message":"invalid argument"},"id":null,"result":null}
+ // documented
+ '19999': BadRequest, // REQUEST_IS_DUPLICATED Duplicated request ID
+ '10001': DuplicateOrderId, // OM_DUPLICATE_ORDERID Duplicated order ID
+ '10002': OrderNotFound, // OM_ORDER_NOT_FOUND Cannot find order ID
+ '10003': CancelPending, // OM_ORDER_PENDING_CANCEL Cannot cancel while order is already in pending cancel status
+ '10004': CancelPending, // OM_ORDER_PENDING_REPLACE Cannot cancel while order is already in pending cancel status
+ '10005': CancelPending, // OM_ORDER_PENDING Cannot cancel while order is already in pending cancel status
+ '11001': InsufficientFunds, // TE_NO_ENOUGH_AVAILABLE_BALANCE Insufficient available balance
+ '11002': InvalidOrder, // TE_INVALID_RISK_LIMIT Invalid risk limit value
+ '11003': InsufficientFunds, // TE_NO_ENOUGH_BALANCE_FOR_NEW_RISK_LIMIT Insufficient available balance
+ '11004': InvalidOrder, // TE_INVALID_LEVERAGE invalid input or new leverage is over maximum allowed leverage
+ '11005': InsufficientFunds, // TE_NO_ENOUGH_BALANCE_FOR_NEW_LEVERAGE Insufficient available balance
+ '11006': ExchangeError, // TE_CANNOT_CHANGE_POSITION_MARGIN_WITHOUT_POSITION Position size is zero. Cannot change margin
+ '11007': ExchangeError, // TE_CANNOT_CHANGE_POSITION_MARGIN_FOR_CROSS_MARGIN Cannot change margin under CrossMargin
+ '11008': ExchangeError, // TE_CANNOT_REMOVE_POSITION_MARGIN_MORE_THAN_ADDED exceeds the maximum removable Margin
+ '11009': ExchangeError, // TE_CANNOT_REMOVE_POSITION_MARGIN_DUE_TO_UNREALIZED_PNL exceeds the maximum removable Margin
+ '11010': InsufficientFunds, // TE_CANNOT_ADD_POSITION_MARGIN_DUE_TO_NO_ENOUGH_AVAILABLE_BALANCE Insufficient available balance
+ '11011': InvalidOrder, // TE_REDUCE_ONLY_ABORT Cannot accept reduce only order
+ '11012': InvalidOrder, // TE_REPLACE_TO_INVALID_QTY Order quantity Error
+ '11013': InvalidOrder, // TE_CONDITIONAL_NO_POSITION Position size is zero. Cannot determine conditional order's quantity
+ '11014': InvalidOrder, // TE_CONDITIONAL_CLOSE_POSITION_WRONG_SIDE Close position conditional order has the same side
+ '11015': InvalidOrder, // TE_CONDITIONAL_TRIGGERED_OR_CANCELED
+ '11016': BadRequest, // TE_ADL_NOT_TRADING_REQUESTED_ACCOUNT Request is routed to the wrong trading engine
+ '11017': ExchangeError, // TE_ADL_CANNOT_FIND_POSITION Cannot find requested position on current account
+ '11018': ExchangeError, // TE_NO_NEED_TO_SETTLE_FUNDING The current account does not need to pay a funding fee
+ '11019': ExchangeError, // TE_FUNDING_ALREADY_SETTLED The current account already pays the funding fee
+ '11020': ExchangeError, // TE_CANNOT_TRANSFER_OUT_DUE_TO_BONUS Withdraw to wallet needs to remove all remaining bonus. However if bonus is used by position or order cost, withdraw fails.
+ '11021': ExchangeError, // TE_INVALID_BONOUS_AMOUNT // Grpc command cannot be negative number Invalid bonus amount
+ '11022': AccountSuspended, // TE_REJECT_DUE_TO_BANNED Account is banned
+ '11023': ExchangeError, // TE_REJECT_DUE_TO_IN_PROCESS_OF_LIQ Account is in the process of liquidation
+ '11024': ExchangeError, // TE_REJECT_DUE_TO_IN_PROCESS_OF_ADL Account is in the process of auto-deleverage
+ '11025': BadRequest, // TE_ROUTE_ERROR Request is routed to the wrong trading engine
+ '11026': ExchangeError, // TE_UID_ACCOUNT_MISMATCH
+ '11027': BadSymbol, // TE_SYMBOL_INVALID Invalid number ID or name
+ '11028': BadSymbol, // TE_CURRENCY_INVALID Invalid currency ID or name
+ '11029': ExchangeError, // TE_ACTION_INVALID Unrecognized request type
+ '11030': ExchangeError, // TE_ACTION_BY_INVALID
+ '11031': DDoSProtection, // TE_SO_NUM_EXCEEDS Number of total conditional orders exceeds the max limit
+ '11032': DDoSProtection, // TE_AO_NUM_EXCEEDS Number of total active orders exceeds the max limit
+ '11033': DuplicateOrderId, // TE_ORDER_ID_DUPLICATE Duplicated order ID
+ '11034': InvalidOrder, // TE_SIDE_INVALID Invalid side
+ '11035': InvalidOrder, // TE_ORD_TYPE_INVALID Invalid OrderType
+ '11036': InvalidOrder, // TE_TIME_IN_FORCE_INVALID Invalid TimeInForce
+ '11037': InvalidOrder, // TE_EXEC_INST_INVALID Invalid ExecType
+ '11038': InvalidOrder, // TE_TRIGGER_INVALID Invalid trigger type
+ '11039': InvalidOrder, // TE_STOP_DIRECTION_INVALID Invalid stop direction type
+ '11040': InvalidOrder, // TE_NO_MARK_PRICE Cannot get valid mark price to create conditional order
+ '11041': InvalidOrder, // TE_NO_INDEX_PRICE Cannot get valid index price to create conditional order
+ '11042': InvalidOrder, // TE_NO_LAST_PRICE Cannot get valid last market price to create conditional order
+ '11043': InvalidOrder, // TE_RISING_TRIGGER_DIRECTLY Conditional order would be triggered immediately
+ '11044': InvalidOrder, // TE_FALLING_TRIGGER_DIRECTLY Conditional order would be triggered immediately
+ '11045': InvalidOrder, // TE_TRIGGER_PRICE_TOO_LARGE Conditional order trigger price is too high
+ '11046': InvalidOrder, // TE_TRIGGER_PRICE_TOO_SMALL Conditional order trigger price is too low
+ '11047': InvalidOrder, // TE_BUY_TP_SHOULD_GT_BASE TakeProfile BUY conditional order trigger price needs to be greater than reference price
+ '11048': InvalidOrder, // TE_BUY_SL_SHOULD_LT_BASE StopLoss BUY condition order price needs to be less than the reference price
+ '11049': InvalidOrder, // TE_BUY_SL_SHOULD_GT_LIQ StopLoss BUY condition order price needs to be greater than liquidation price or it will not trigger
+ '11050': InvalidOrder, // TE_SELL_TP_SHOULD_LT_BASE TakeProfile SELL conditional order trigger price needs to be less than reference price
+ '11051': InvalidOrder, // TE_SELL_SL_SHOULD_LT_LIQ StopLoss SELL condition order price needs to be less than liquidation price or it will not trigger
+ '11052': InvalidOrder, // TE_SELL_SL_SHOULD_GT_BASE StopLoss SELL condition order price needs to be greater than the reference price
+ '11053': InvalidOrder, // TE_PRICE_TOO_LARGE
+ '11054': InvalidOrder, // TE_PRICE_WORSE_THAN_BANKRUPT Order price cannot be more aggressive than bankrupt price if this order has instruction to close a position
+ '11055': InvalidOrder, // TE_PRICE_TOO_SMALL Order price is too low
+ '11056': InvalidOrder, // TE_QTY_TOO_LARGE Order quantity is too large
+ '11057': InvalidOrder, // TE_QTY_NOT_MATCH_REDUCE_ONLY Does not allow ReduceOnly order without position
+ '11058': InvalidOrder, // TE_QTY_TOO_SMALL Order quantity is too small
+ '11059': InvalidOrder, // TE_TP_SL_QTY_NOT_MATCH_POS Position size is zero. Cannot accept any TakeProfit or StopLoss order
+ '11060': InvalidOrder, // TE_SIDE_NOT_CLOSE_POS TakeProfit or StopLoss order has wrong side. Cannot close position
+ '11061': CancelPending, // TE_ORD_ALREADY_PENDING_CANCEL Repeated cancel request
+ '11062': InvalidOrder, // TE_ORD_ALREADY_CANCELED Order is already canceled
+ '11063': InvalidOrder, // TE_ORD_STATUS_CANNOT_CANCEL Order is not able to be canceled under current status
+ '11064': InvalidOrder, // TE_ORD_ALREADY_PENDING_REPLACE Replace request is rejected because order is already in pending replace status
+ '11065': InvalidOrder, // TE_ORD_REPLACE_NOT_MODIFIED Replace request does not modify any parameters of the order
+ '11066': InvalidOrder, // TE_ORD_STATUS_CANNOT_REPLACE Order is not able to be replaced under current status
+ '11067': InvalidOrder, // TE_CANNOT_REPLACE_PRICE Market conditional order cannot change price
+ '11068': InvalidOrder, // TE_CANNOT_REPLACE_QTY Condtional order for closing position cannot change order quantity, since the order quantity is determined by position size already
+ '11069': ExchangeError, // TE_ACCOUNT_NOT_IN_RANGE The account ID in the request is not valid or is not in the range of the current process
+ '11070': BadSymbol, // TE_SYMBOL_NOT_IN_RANGE The symbol is invalid
+ '11071': InvalidOrder, // TE_ORD_STATUS_CANNOT_TRIGGER
+ '11072': InvalidOrder, // TE_TKFR_NOT_IN_RANGE The fee value is not valid
+ '11073': InvalidOrder, // TE_MKFR_NOT_IN_RANGE The fee value is not valid
+ '11074': InvalidOrder, // TE_CANNOT_ATTACH_TP_SL Order request cannot contain TP/SL parameters when the account already has positions
+ '11075': InvalidOrder, // TE_TP_TOO_LARGE TakeProfit price is too large
+ '11076': InvalidOrder, // TE_TP_TOO_SMALL TakeProfit price is too small
+ '11077': InvalidOrder, // TE_TP_TRIGGER_INVALID Invalid trigger type
+ '11078': InvalidOrder, // TE_SL_TOO_LARGE StopLoss price is too large
+ '11079': InvalidOrder, // TE_SL_TOO_SMALL StopLoss price is too small
+ '11080': InvalidOrder, // TE_SL_TRIGGER_INVALID Invalid trigger type
+ '11081': InvalidOrder, // TE_RISK_LIMIT_EXCEEDS Total potential position breaches current risk limit
+ '11082': InsufficientFunds, // TE_CANNOT_COVER_ESTIMATE_ORDER_LOSS The remaining balance cannot cover the potential unrealized PnL for this new order
+ '11083': InvalidOrder, // TE_TAKE_PROFIT_ORDER_DUPLICATED TakeProfit order already exists
+ '11084': InvalidOrder, // TE_STOP_LOSS_ORDER_DUPLICATED StopLoss order already exists
+ '11085': DuplicateOrderId, // TE_CL_ORD_ID_DUPLICATE ClOrdId is duplicated
+ '11086': InvalidOrder, // TE_PEG_PRICE_TYPE_INVALID PegPriceType is invalid
+ '11087': InvalidOrder, // TE_BUY_TS_SHOULD_LT_BASE The trailing order's StopPrice should be less than the current last price
+ '11088': InvalidOrder, // TE_BUY_TS_SHOULD_GT_LIQ The traling order's StopPrice should be greater than the current liquidation price
+ '11089': InvalidOrder, // TE_SELL_TS_SHOULD_LT_LIQ The traling order's StopPrice should be greater than the current last price
+ '11090': InvalidOrder, // TE_SELL_TS_SHOULD_GT_BASE The traling order's StopPrice should be less than the current liquidation price
+ '11091': InvalidOrder, // TE_BUY_REVERT_VALUE_SHOULD_LT_ZERO The PegOffset should be less than zero
+ '11092': InvalidOrder, // TE_SELL_REVERT_VALUE_SHOULD_GT_ZERO The PegOffset should be greater than zero
+ '11093': InvalidOrder, // TE_BUY_TTP_SHOULD_ACTIVATE_ABOVE_BASE The activation price should be greater than the current last price
+ '11094': InvalidOrder, // TE_SELL_TTP_SHOULD_ACTIVATE_BELOW_BASE The activation price should be less than the current last price
+ '11095': InvalidOrder, // TE_TRAILING_ORDER_DUPLICATED A trailing order exists already
+ '11096': InvalidOrder, // TE_CLOSE_ORDER_CANNOT_ATTACH_TP_SL An order to close position cannot have trailing instruction
+ '11097': BadRequest, // TE_CANNOT_FIND_WALLET_OF_THIS_CURRENCY This crypto is not supported
+ '11098': BadRequest, // TE_WALLET_INVALID_ACTION Invalid action on wallet
+ '11099': ExchangeError, // TE_WALLET_VID_UNMATCHED Wallet operation request has a wrong wallet vid
+ '11100': InsufficientFunds, // TE_WALLET_INSUFFICIENT_BALANCE Wallet has insufficient balance
+ '11101': InsufficientFunds, // TE_WALLET_INSUFFICIENT_LOCKED_BALANCE Locked balance in wallet is not enough for unlock/withdraw request
+ '11102': BadRequest, // TE_WALLET_INVALID_DEPOSIT_AMOUNT Deposit amount must be greater than zero
+ '11103': BadRequest, // TE_WALLET_INVALID_WITHDRAW_AMOUNT Withdraw amount must be less than zero
+ '11104': BadRequest, // TE_WALLET_REACHED_MAX_AMOUNT Deposit makes wallet exceed max amount allowed
+ '11105': InsufficientFunds, // TE_PLACE_ORDER_INSUFFICIENT_BASE_BALANCE Insufficient funds in base wallet
+ '11106': InsufficientFunds, // TE_PLACE_ORDER_INSUFFICIENT_QUOTE_BALANCE Insufficient funds in quote wallet
+ '11107': ExchangeError, // TE_CANNOT_CONNECT_TO_REQUEST_SEQ TradingEngine failed to connect with CrossEngine
+ '11108': InvalidOrder, // TE_CANNOT_REPLACE_OR_CANCEL_MARKET_ORDER Cannot replace/amend market order
+ '11109': InvalidOrder, // TE_CANNOT_REPLACE_OR_CANCEL_IOC_ORDER Cannot replace/amend ImmediateOrCancel order
+ '11110': InvalidOrder, // TE_CANNOT_REPLACE_OR_CANCEL_FOK_ORDER Cannot replace/amend FillOrKill order
+ '11111': InvalidOrder, // TE_MISSING_ORDER_ID OrderId is missing
+ '11112': InvalidOrder, // TE_QTY_TYPE_INVALID QtyType is invalid
+ '11113': BadRequest, // TE_USER_ID_INVALID UserId is invalid
+ '11114': InvalidOrder, // TE_ORDER_VALUE_TOO_LARGE Order value is too large
+ '11115': InvalidOrder, // TE_ORDER_VALUE_TOO_SMALL Order value is too small
+ // not documented
+ '30018': BadRequest, // {"code":30018,"msg":"phemex.data.size.uplimt","data":null}
+ '39996': PermissionDenied, // {"code": "39996","msg": "Access denied."}
+ },
+ 'broad': {
+ 'Failed to find api-key': AuthenticationError, // {"msg":"Failed to find api-key 1c5ec63fd-660d-43ea-847a-0d3ba69e106e","code":10500}
+ 'Missing required parameter': BadRequest, // {"msg":"Missing required parameter","code":10500}
+ 'API Signature verification failed': AuthenticationError, // {"msg":"API Signature verification failed.","code":10500}
+ },
+ },
+ 'options': {
+ 'x-phemex-request-expiry': 60, // in seconds
+ 'createOrderByQuoteRequiresPrice': true,
+ },
+ });
+ }
+
+ parseSafeFloat (value = undefined) {
+ if (value === undefined) {
+ return value;
+ }
+ value = value.replace (',', '');
+ const parts = value.split (' ');
+ return this.safeFloat (parts, 0);
+ }
+
+ parseSwapMarket (market) {
+ //
+ // {
+ // "symbol":"BTCUSD",
+ // "displaySymbol":"BTC / USD",
+ // "indexSymbol":".BTC",
+ // "markSymbol":".MBTC",
+ // "fundingRateSymbol":".BTCFR",
+ // "fundingRate8hSymbol":".BTCFR8H",
+ // "contractUnderlyingAssets":"USD",
+ // "settleCurrency":"BTC",
+ // "quoteCurrency":"USD",
+ // "contractSize":"1 USD",
+ // "lotSize":1,
+ // "tickSize":0.5,
+ // "priceScale":4,
+ // "ratioScale":8,
+ // "pricePrecision":1,
+ // "minPriceEp":5000,
+ // "maxPriceEp":10000000000,
+ // "maxOrderQty":1000000,
+ // "type":"Perpetual"
+ // "steps":"50",
+ // "riskLimits":[
+ // {"limit":100,"initialMargin":"1.0%","initialMarginEr":1000000,"maintenanceMargin":"0.5%","maintenanceMarginEr":500000},
+ // {"limit":150,"initialMargin":"1.5%","initialMarginEr":1500000,"maintenanceMargin":"1.0%","maintenanceMarginEr":1000000},
+ // {"limit":200,"initialMargin":"2.0%","initialMarginEr":2000000,"maintenanceMargin":"1.5%","maintenanceMarginEr":1500000},
+ // ],
+ // "underlyingSymbol":".BTC",
+ // "baseCurrency":"BTC",
+ // "settlementCurrency":"BTC",
+ // "valueScale":8,
+ // "defaultLeverage":0,
+ // "maxLeverage":100,
+ // "initMarginEr":"1000000",
+ // "maintMarginEr":"500000",
+ // "defaultRiskLimitEv":10000000000,
+ // "deleverage":true,
+ // "makerFeeRateEr":-250000,
+ // "takerFeeRateEr":750000,
+ // "fundingInterval":8,
+ // "marketUrl":"https://phemex.com/trade/BTCUSD",
+ // "description":"BTCUSD is a BTC/USD perpetual contract priced on the .BTC Index. Each contract is worth 1 USD of Bitcoin. Funding is paid and received every 8 hours. At UTC time: 00:00, 08:00, 16:00.",
+ // }
+ //
+ const id = this.safeString (market, 'symbol');
+ const baseId = this.safeString (market, 'baseCurrency', 'contractUnderlyingAssets');
+ const quoteId = this.safeString (market, 'quoteCurrency');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const type = this.safeStringLower (market, 'type');
+ let taker = undefined;
+ let maker = undefined;
+ let inverse = false;
+ const spot = false;
+ const swap = true;
+ const settlementCurrencyId = this.safeString (market, 'settlementCurrency');
+ if (settlementCurrencyId !== quoteId) {
+ inverse = true;
+ }
+ const linear = !inverse;
+ const precision = {
+ 'amount': this.safeFloat (market, 'lotSize'),
+ 'price': this.safeFloat (market, 'tickSize'),
+ };
+ const priceScale = this.safeInteger (market, 'priceScale');
+ const ratioScale = this.safeInteger (market, 'ratioScale');
+ const valueScale = this.safeInteger (market, 'valueScale');
+ const minPriceEp = this.safeFloat (market, 'minPriceEp');
+ const maxPriceEp = this.safeFloat (market, 'maxPriceEp');
+ const makerFeeRateEr = this.safeFloat (market, 'makerFeeRateEr');
+ const takerFeeRateEr = this.safeFloat (market, 'takerFeeRateEr');
+ if (makerFeeRateEr !== undefined) {
+ maker = this.fromEn (makerFeeRateEr, ratioScale, 0.00000001);
+ }
+ if (takerFeeRateEr !== undefined) {
+ taker = this.fromEn (takerFeeRateEr, ratioScale, 0.00000001);
+ }
+ const limits = {
+ 'amount': {
+ 'min': precision['amount'],
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': this.fromEn (minPriceEp, priceScale, precision['price']),
+ 'max': this.fromEn (maxPriceEp, priceScale, precision['price']),
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': this.parseSafeFloat (this.safeString (market, 'maxOrderQty')),
+ },
+ };
+ const active = undefined;
+ return {
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'info': market,
+ 'type': type,
+ 'spot': spot,
+ 'swap': swap,
+ 'linear': linear,
+ 'inverse': inverse,
+ 'active': active,
+ 'taker': taker,
+ 'maker': maker,
+ 'priceScale': priceScale,
+ 'valueScale': valueScale,
+ 'ratioScale': ratioScale,
+ 'precision': precision,
+ 'limits': limits,
+ };
+ }
+
+ parseSpotMarket (market) {
+ //
+ // {
+ // "symbol":"sBTCUSDT",
+ // "displaySymbol":"BTC / USDT",
+ // "quoteCurrency":"USDT",
+ // "pricePrecision":2,
+ // "type":"Spot",
+ // "baseCurrency":"BTC",
+ // "baseTickSize":"0.000001 BTC",
+ // "baseTickSizeEv":100,
+ // "quoteTickSize":"0.01 USDT",
+ // "quoteTickSizeEv":1000000,
+ // "minOrderValue":"10 USDT",
+ // "minOrderValueEv":1000000000,
+ // "maxBaseOrderSize":"1000 BTC",
+ // "maxBaseOrderSizeEv":100000000000,
+ // "maxOrderValue":"5,000,000 USDT",
+ // "maxOrderValueEv":500000000000000,
+ // "defaultTakerFee":"0.001",
+ // "defaultTakerFeeEr":100000,
+ // "defaultMakerFee":"0.001",
+ // "defaultMakerFeeEr":100000,
+ // "baseQtyPrecision":6,
+ // "quoteQtyPrecision":2
+ // }
+ //
+ const type = this.safeStringLower (market, 'type');
+ const id = this.safeString (market, 'symbol');
+ const quoteId = this.safeString (market, 'quoteCurrency');
+ const baseId = this.safeString (market, 'baseCurrency');
+ const linear = undefined;
+ const inverse = undefined;
+ const spot = true;
+ const swap = false;
+ const taker = this.safeFloat (market, 'defaultTakerFee');
+ const maker = this.safeFloat (market, 'defaultMakerFee');
+ const precision = {
+ 'amount': this.parseSafeFloat (this.safeString (market, 'baseTickSize')),
+ 'price': this.parseSafeFloat (this.safeString (market, 'quoteTickSize')),
+ };
+ const limits = {
+ 'amount': {
+ 'min': precision['amount'],
+ 'max': this.parseSafeFloat (this.safeString (market, 'maxBaseOrderSize')),
+ },
+ 'price': {
+ 'min': precision['price'],
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': this.parseSafeFloat (this.safeString (market, 'minOrderValue')),
+ 'max': this.parseSafeFloat (this.safeString (market, 'maxOrderValue')),
+ },
+ };
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const active = undefined;
+ return {
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'info': market,
+ 'type': type,
+ 'spot': spot,
+ 'swap': swap,
+ 'linear': linear,
+ 'inverse': inverse,
+ 'active': active,
+ 'taker': taker,
+ 'maker': maker,
+ 'precision': precision,
+ 'priceScale': 8,
+ 'valueScale': 8,
+ 'ratioScale': 8,
+ 'limits': limits,
+ };
+ }
+
+ async fetchMarkets (params = {}) {
+ const v2Products = await this.publicGetCfgV2Products (params);
+ //
+ // {
+ // "code":0,
+ // "msg":"OK",
+ // "data":{
+ // "ratioScale":8,
+ // "currencies":[
+ // {"currency":"BTC","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"Bitcoin"},
+ // {"currency":"USD","valueScale":4,"minValueEv":1,"maxValueEv":500000000000000,"name":"USD"},
+ // {"currency":"USDT","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"TetherUS"},
+ // ],
+ // "products":[
+ // {
+ // "symbol":"BTCUSD",
+ // "displaySymbol":"BTC / USD",
+ // "indexSymbol":".BTC",
+ // "markSymbol":".MBTC",
+ // "fundingRateSymbol":".BTCFR",
+ // "fundingRate8hSymbol":".BTCFR8H",
+ // "contractUnderlyingAssets":"USD",
+ // "settleCurrency":"BTC",
+ // "quoteCurrency":"USD",
+ // "contractSize":1.0,
+ // "lotSize":1,
+ // "tickSize":0.5,
+ // "priceScale":4,
+ // "ratioScale":8,
+ // "pricePrecision":1,
+ // "minPriceEp":5000,
+ // "maxPriceEp":10000000000,
+ // "maxOrderQty":1000000,
+ // "type":"Perpetual"
+ // },
+ // {
+ // "symbol":"sBTCUSDT",
+ // "displaySymbol":"BTC / USDT",
+ // "quoteCurrency":"USDT",
+ // "pricePrecision":2,
+ // "type":"Spot",
+ // "baseCurrency":"BTC",
+ // "baseTickSize":"0.000001 BTC",
+ // "baseTickSizeEv":100,
+ // "quoteTickSize":"0.01 USDT",
+ // "quoteTickSizeEv":1000000,
+ // "minOrderValue":"10 USDT",
+ // "minOrderValueEv":1000000000,
+ // "maxBaseOrderSize":"1000 BTC",
+ // "maxBaseOrderSizeEv":100000000000,
+ // "maxOrderValue":"5,000,000 USDT",
+ // "maxOrderValueEv":500000000000000,
+ // "defaultTakerFee":"0.001",
+ // "defaultTakerFeeEr":100000,
+ // "defaultMakerFee":"0.001",
+ // "defaultMakerFeeEr":100000,
+ // "baseQtyPrecision":6,
+ // "quoteQtyPrecision":2
+ // },
+ // ],
+ // "riskLimits":[
+ // {
+ // "symbol":"BTCUSD",
+ // "steps":"50",
+ // "riskLimits":[
+ // {"limit":100,"initialMargin":"1.0%","initialMarginEr":1000000,"maintenanceMargin":"0.5%","maintenanceMarginEr":500000},
+ // {"limit":150,"initialMargin":"1.5%","initialMarginEr":1500000,"maintenanceMargin":"1.0%","maintenanceMarginEr":1000000},
+ // {"limit":200,"initialMargin":"2.0%","initialMarginEr":2000000,"maintenanceMargin":"1.5%","maintenanceMarginEr":1500000},
+ // ]
+ // },
+ // ],
+ // "leverages":[
+ // {"initialMargin":"1.0%","initialMarginEr":1000000,"options":[1,2,3,5,10,25,50,100]},
+ // {"initialMargin":"1.5%","initialMarginEr":1500000,"options":[1,2,3,5,10,25,50,66]},
+ // {"initialMargin":"2.0%","initialMarginEr":2000000,"options":[1,2,3,5,10,25,33,50]},
+ // ]
+ // }
+ // }
+ //
+ const v1Products = await this.v1GetExchangePublicProducts (params);
+ const v1ProductsData = this.safeValue (v1Products, 'data', []);
+ //
+ // {
+ // "code":0,
+ // "msg":"OK",
+ // "data":[
+ // {
+ // "symbol":"BTCUSD",
+ // "underlyingSymbol":".BTC",
+ // "quoteCurrency":"USD",
+ // "baseCurrency":"BTC",
+ // "settlementCurrency":"BTC",
+ // "maxOrderQty":1000000,
+ // "maxPriceEp":100000000000000,
+ // "lotSize":1,
+ // "tickSize":"0.5",
+ // "contractSize":"1 USD",
+ // "priceScale":4,
+ // "ratioScale":8,
+ // "valueScale":8,
+ // "defaultLeverage":0,
+ // "maxLeverage":100,
+ // "initMarginEr":"1000000",
+ // "maintMarginEr":"500000",
+ // "defaultRiskLimitEv":10000000000,
+ // "deleverage":true,
+ // "makerFeeRateEr":-250000,
+ // "takerFeeRateEr":750000,
+ // "fundingInterval":8,
+ // "marketUrl":"https://phemex.com/trade/BTCUSD",
+ // "description":"BTCUSD is a BTC/USD perpetual contract priced on the .BTC Index. Each contract is worth 1 USD of Bitcoin. Funding is paid and received every 8 hours. At UTC time: 00:00, 08:00, 16:00.",
+ // "type":"Perpetual"
+ // },
+ // ]
+ // }
+ //
+ const v2ProductsData = this.safeValue (v2Products, 'data', {});
+ const products = this.safeValue (v2ProductsData, 'products', []);
+ const riskLimits = this.safeValue (v2ProductsData, 'riskLimits', []);
+ const riskLimitsById = this.indexBy (riskLimits, 'symbol');
+ const v1ProductsById = this.indexBy (v1ProductsData, 'symbol');
+ const result = [];
+ for (let i = 0; i < products.length; i++) {
+ let market = products[i];
+ const type = this.safeStringLower (market, 'type');
+ if (type === 'perpetual') {
+ const id = this.safeString (market, 'symbol');
+ const riskLimitValues = this.safeValue (riskLimitsById, id, {});
+ market = this.extend (market, riskLimitValues);
+ const v1ProductsValues = this.safeValue (v1ProductsById, id, {});
+ market = this.extend (market, v1ProductsValues);
+ market = this.parseSwapMarket (market);
+ } else {
+ market = this.parseSpotMarket (market);
+ }
+ result.push (market);
+ }
+ return result;
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCfgV2Products (params);
+ //
+ // {
+ // "code":0,
+ // "msg":"OK",
+ // "data":{
+ // ...,
+ // "currencies":[
+ // {"currency":"BTC","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"Bitcoin"},
+ // {"currency":"USD","valueScale":4,"minValueEv":1,"maxValueEv":500000000000000,"name":"USD"},
+ // {"currency":"USDT","valueScale":8,"minValueEv":1,"maxValueEv":5000000000000000000,"name":"TetherUS"},
+ // ],
+ // ...
+ // }
+ // }
+ const data = this.safeValue (response, 'data', {});
+ const currencies = this.safeValue (data, 'currencies', []);
+ const result = {};
+ for (let i = 0; i < currencies.length; i++) {
+ const currency = currencies[i];
+ const id = this.safeString (currency, 'currency');
+ const name = this.safeString (currency, 'name');
+ const code = this.safeCurrencyCode (id);
+ const valueScale = this.safeInteger (currency, 'valueScale');
+ const minValueEv = this.safeFloat (currency, 'minValueEv');
+ const maxValueEv = this.safeFloat (currency, 'maxValueEv');
+ let minAmount = undefined;
+ let maxAmount = undefined;
+ let precision = undefined;
+ if (valueScale !== undefined) {
+ precision = Math.pow (10, -valueScale);
+ precision = parseFloat (this.decimalToPrecision (precision, ROUND, 0.00000001, this.precisionMode));
+ if (minValueEv !== undefined) {
+ minAmount = parseFloat (this.decimalToPrecision (minValueEv * precision, ROUND, 0.00000001, this.precisionMode));
+ }
+ if (maxValueEv !== undefined) {
+ maxAmount = parseFloat (this.decimalToPrecision (maxValueEv * precision, ROUND, 0.00000001, this.precisionMode));
+ }
+ }
+ result[code] = {
+ 'id': id,
+ 'info': currency,
+ 'code': code,
+ 'name': name,
+ 'active': undefined,
+ 'fee': undefined,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': minAmount,
+ 'max': maxAmount,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ 'valueScale': valueScale,
+ };
+ }
+ return result;
+ }
+
+ parseBidAsk (bidask, priceKey = 0, amountKey = 1, market = undefined) {
+ if (market === undefined) {
+ throw new ArgumentsRequired (this.id + ' parseBidAsk requires a market argument');
+ }
+ let amount = this.safeFloat (bidask, amountKey);
+ if (market['spot']) {
+ amount = this.fromEv (amount, market);
+ }
+ return [
+ this.fromEp (this.safeFloat (bidask, priceKey), market),
+ amount,
+ ];
+ }
+
+ parseOrderBook (orderbook, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 0, amountKey = 1, market = undefined) {
+ const result = {
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'nonce': undefined,
+ };
+ const sides = [ bidsKey, asksKey ];
+ for (let i = 0; i < sides.length; i++) {
+ const side = sides[i];
+ const orders = [];
+ const bidasks = this.safeValue (orderbook, side);
+ for (let k = 0; k < bidasks.length; k++) {
+ orders.push (this.parseBidAsk (bidasks[k], priceKey, amountKey, market));
+ }
+ result[side] = orders;
+ }
+ result[bidsKey] = this.sortBy (result[bidsKey], 0, true);
+ result[asksKey] = this.sortBy (result[asksKey], 0);
+ return result;
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ // 'id': 123456789, // optional request id
+ };
+ const response = await this.v1GetMdOrderbook (this.extend (request, params));
+ //
+ // {
+ // "error": null,
+ // "id": 0,
+ // "result": {
+ // "book": {
+ // "asks": [
+ // [ 23415000000, 105262000 ],
+ // [ 23416000000, 147914000 ],
+ // [ 23419000000, 160914000 ],
+ // ],
+ // "bids": [
+ // [ 23360000000, 32995000 ],
+ // [ 23359000000, 221887000 ],
+ // [ 23356000000, 284599000 ],
+ // ],
+ // },
+ // "depth": 30,
+ // "sequence": 1592059928,
+ // "symbol": "sETHUSDT",
+ // "timestamp": 1592387340020000955,
+ // "type": "snapshot"
+ // }
+ // }
+ //
+ const result = this.safeValue (response, 'result', {});
+ const book = this.safeValue (result, 'book', {});
+ const timestamp = this.safeIntegerProduct (result, 'timestamp', 0.000001);
+ const orderbook = this.parseOrderBook (book, timestamp, 'bids', 'asks', 0, 1, market);
+ orderbook['nonce'] = this.safeInteger (result, 'sequence');
+ return orderbook;
+ }
+
+ toEn (n, scale, precision) {
+ return parseInt (this.decimalToPrecision (n * Math.pow (10, scale), ROUND, precision, DECIMAL_PLACES));
+ }
+
+ toEv (amount, market = undefined) {
+ if ((amount === undefined) || (market === undefined)) {
+ return amount;
+ }
+ return this.toEn (amount, market['valueScale'], 0);
+ }
+
+ toEp (price, market = undefined) {
+ if ((price === undefined) || (market === undefined)) {
+ return price;
+ }
+ return this.toEn (price, market['priceScale'], 0);
+ }
+
+ fromEn (en, scale, precision, precisionMode = undefined) {
+ precisionMode = (precisionMode === undefined) ? this.precisionMode : precisionMode;
+ return parseFloat (this.decimalToPrecision (en * Math.pow (10, -scale), ROUND, precision, precisionMode));
+ }
+
+ fromEp (ep, market = undefined) {
+ if ((ep === undefined) || (market === undefined)) {
+ return ep;
+ }
+ return this.fromEn (ep, market['priceScale'], market['precision']['price']);
+ }
+
+ fromEv (ev, market = undefined) {
+ if ((ev === undefined) || (market === undefined)) {
+ return ev;
+ }
+ if (market['spot']) {
+ return this.fromEn (ev, market['valueScale'], market['precision']['amount']);
+ } else {
+ return this.fromEn (ev, market['valueScale'], 1 / Math.pow (10, market['valueScale']));
+ }
+ }
+
+ fromEr (er, market = undefined) {
+ if ((er === undefined) || (market === undefined)) {
+ return er;
+ }
+ return this.fromEn (er, market['ratioScale'], 0.00000001);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1592467200, // timestamp
+ // 300, // interval
+ // 23376000000, // last
+ // 23322000000, // open
+ // 23381000000, // high
+ // 23315000000, // low
+ // 23367000000, // close
+ // 208671000, // base volume
+ // 48759063370, // quote volume
+ // ]
+ //
+ return [
+ this.safeTimestamp (ohlcv, 0),
+ this.fromEp (this.safeFloat (ohlcv, 3), market),
+ this.fromEp (this.safeFloat (ohlcv, 4), market),
+ this.fromEp (this.safeFloat (ohlcv, 5), market),
+ this.fromEp (this.safeFloat (ohlcv, 6), market),
+ this.fromEv (this.safeFloat (ohlcv, 7), market),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ const request = {
+ // 'symbol': market['id'],
+ 'resolution': this.timeframes[timeframe],
+ // 'from': 1588830682, // seconds
+ // 'to': this.seconds (),
+ };
+ const duration = this.parseTimeframe (timeframe);
+ const now = this.seconds ();
+ if (since !== undefined) {
+ if (limit === undefined) {
+ limit = 2000; // max 2000
+ }
+ since = parseInt (since / 1000);
+ request['from'] = since;
+ // time ranges ending in the future are not accepted
+ // https://github.com/ccxt/ccxt/issues/8050
+ request['to'] = Math.min (now, this.sum (since, duration * limit));
+ } else if (limit !== undefined) {
+ limit = Math.min (limit, 2000);
+ request['from'] = now - duration * this.sum (limit, 1);
+ request['to'] = now;
+ } else {
+ throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument, or a limit argument, or both');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ request['symbol'] = market['id'];
+ const response = await this.publicGetMdKline (this.extend (request, params));
+ //
+ // {
+ // "code":0,
+ // "msg":"OK",
+ // "data":{
+ // "total":-1,
+ // "rows":[
+ // [1592467200,300,23376000000,23322000000,23381000000,23315000000,23367000000,208671000,48759063370],
+ // [1592467500,300,23367000000,23314000000,23390000000,23311000000,23331000000,234820000,54848948710],
+ // [1592467800,300,23331000000,23385000000,23391000000,23326000000,23387000000,152931000,35747882250],
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const rows = this.safeValue (data, 'rows', []);
+ return this.parseOHLCVs (rows, market, timeframe, since, limit);
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // spot
+ //
+ // {
+ // "askEp": 943836000000,
+ // "bidEp": 943601000000,
+ // "highEp": 955946000000,
+ // "lastEp": 943803000000,
+ // "lowEp": 924973000000,
+ // "openEp": 948693000000,
+ // "symbol": "sBTCUSDT",
+ // "timestamp": 1592471203505728630,
+ // "turnoverEv": 111822826123103,
+ // "volumeEv": 11880532281
+ // }
+ //
+ // swap
+ //
+ // {
+ // "askEp": 2332500,
+ // "bidEp": 2331000,
+ // "fundingRateEr": 10000,
+ // "highEp": 2380000,
+ // "indexEp": 2329057,
+ // "lastEp": 2331500,
+ // "lowEp": 2274000,
+ // "markEp": 2329232,
+ // "openEp": 2337500,
+ // "openInterest": 1298050,
+ // "predFundingRateEr": 19921,
+ // "symbol": "ETHUSD",
+ // "timestamp": 1592474241582701416,
+ // "turnoverEv": 47228362330,
+ // "volume": 4053863
+ // }
+ //
+ const marketId = this.safeString (ticker, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
+ const timestamp = this.safeIntegerProduct (ticker, 'timestamp', 0.000001);
+ const last = this.fromEp (this.safeFloat (ticker, 'lastEp'), market);
+ const quoteVolume = this.fromEp (this.safeFloat (ticker, 'turnoverEv'), market);
+ let baseVolume = this.safeFloat (ticker, 'volume');
+ if (baseVolume === undefined) {
+ baseVolume = this.fromEv (this.safeFloat (ticker, 'volumeEv'));
+ }
+ let vwap = undefined;
+ if ((market !== undefined) && (market['spot'])) {
+ vwap = this.vwap (baseVolume, quoteVolume);
+ }
+ let change = undefined;
+ let percentage = undefined;
+ let average = undefined;
+ const open = this.fromEp (this.safeFloat (ticker, 'openEp'), market);
+ if ((open !== undefined) && (last !== undefined)) {
+ change = last - open;
+ if (open > 0) {
+ percentage = change / open * 100;
+ }
+ average = this.sum (open, last) / 2;
+ }
+ const result = {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.fromEp (this.safeFloat (ticker, 'highEp'), market),
+ 'low': this.fromEp (this.safeFloat (ticker, 'lowEp'), market),
+ 'bid': this.fromEp (this.safeFloat (ticker, 'bidEp'), market),
+ 'bidVolume': undefined,
+ 'ask': this.fromEp (this.safeFloat (ticker, 'askEp'), market),
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined, // previous day close
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ return result;
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ // 'id': 123456789, // optional request id
+ };
+ const method = market['spot'] ? 'v1GetMdSpotTicker24hr' : 'v1GetMdTicker24hr';
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "error": null,
+ // "id": 0,
+ // "result": {
+ // "askEp": 943836000000,
+ // "bidEp": 943601000000,
+ // "highEp": 955946000000,
+ // "lastEp": 943803000000,
+ // "lowEp": 924973000000,
+ // "openEp": 948693000000,
+ // "symbol": "sBTCUSDT",
+ // "timestamp": 1592471203505728630,
+ // "turnoverEv": 111822826123103,
+ // "volumeEv": 11880532281
+ // }
+ // }
+ //
+ // swap
+ //
+ // {
+ // "error": null,
+ // "id": 0,
+ // "result": {
+ // "askEp": 2332500,
+ // "bidEp": 2331000,
+ // "fundingRateEr": 10000,
+ // "highEp": 2380000,
+ // "indexEp": 2329057,
+ // "lastEp": 2331500,
+ // "lowEp": 2274000,
+ // "markEp": 2329232,
+ // "openEp": 2337500,
+ // "openInterest": 1298050,
+ // "predFundingRateEr": 19921,
+ // "symbol": "ETHUSD",
+ // "timestamp": 1592474241582701416,
+ // "turnoverEv": 47228362330,
+ // "volume": 4053863
+ // }
+ // }
+ //
+ const result = this.safeValue (response, 'result', {});
+ return this.parseTicker (result, market);
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ // 'id': 123456789, // optional request id
+ };
+ const response = await this.v1GetMdTrade (this.extend (request, params));
+ //
+ // {
+ // "error": null,
+ // "id": 0,
+ // "result": {
+ // "sequence": 1315644947,
+ // "symbol": "BTCUSD",
+ // "trades": [
+ // [ 1592541746712239749, 13156448570000, "Buy", 93070000, 40173 ],
+ // [ 1592541740434625085, 13156447110000, "Sell", 93065000, 5000 ],
+ // [ 1592541732958241616, 13156441390000, "Buy", 93070000, 3460 ],
+ // ],
+ // "type": "snapshot"
+ // }
+ // }
+ //
+ const result = this.safeValue (response, 'result', {});
+ const trades = this.safeValue (result, 'trades', []);
+ return this.parseTrades (trades, market, since, limit);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // [
+ // 1592541746712239749,
+ // 13156448570000,
+ // "Buy",
+ // 93070000,
+ // 40173
+ // ]
+ //
+ // fetchMyTrades (private)
+ //
+ // spot
+ //
+ // {
+ // "qtyType": "ByQuote",
+ // "transactTimeNs": 1589450974800550100,
+ // "clOrdID": "8ba59d40-df25-d4b0-14cf-0703f44e9690",
+ // "orderID": "b2b7018d-f02f-4c59-b4cf-051b9c2d2e83",
+ // "symbol": "sBTCUSDT",
+ // "side": "Buy",
+ // "priceEP": 970056000000,
+ // "baseQtyEv": 0,
+ // "quoteQtyEv": 1000000000,
+ // "action": "New",
+ // "execStatus": "MakerFill",
+ // "ordStatus": "Filled",
+ // "ordType": "Limit",
+ // "execInst": "None",
+ // "timeInForce": "GoodTillCancel",
+ // "stopDirection": "UNSPECIFIED",
+ // "tradeType": "Trade",
+ // "stopPxEp": 0,
+ // "execId": "c6bd8979-07ba-5946-b07e-f8b65135dbb1",
+ // "execPriceEp": 970056000000,
+ // "execBaseQtyEv": 103000,
+ // "execQuoteQtyEv": 999157680,
+ // "leavesBaseQtyEv": 0,
+ // "leavesQuoteQtyEv": 0,
+ // "execFeeEv": 0,
+ // "feeRateEr": 0
+ // }
+ //
+ // swap
+ //
+ // {
+ // "transactTimeNs": 1578026629824704800,
+ // "symbol": "BTCUSD",
+ // "currency": "BTC",
+ // "action": "Replace",
+ // "side": "Sell",
+ // "tradeType": "Trade",
+ // "execQty": 700,
+ // "execPriceEp": 71500000,
+ // "orderQty": 700,
+ // "priceEp": 71500000,
+ // "execValueEv": 9790209,
+ // "feeRateEr": -25000,
+ // "execFeeEv": -2447,
+ // "ordType": "Limit",
+ // "execID": "b01671a1-5ddc-5def-b80a-5311522fd4bf",
+ // "orderID": "b63bc982-be3a-45e0-8974-43d6375fb626",
+ // "clOrdID": "uuid-1577463487504",
+ // "execStatus": "MakerFill"
+ // }
+ //
+ let price = undefined;
+ let amount = undefined;
+ let timestamp = undefined;
+ let id = undefined;
+ let side = undefined;
+ let cost = undefined;
+ let type = undefined;
+ let fee = undefined;
+ const marketId = this.safeString (trade, 'symbol');
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
+ let orderId = undefined;
+ let takerOrMaker = undefined;
+ if (Array.isArray (trade)) {
+ const tradeLength = trade.length;
+ timestamp = this.safeIntegerProduct (trade, 0, 0.000001);
+ if (tradeLength > 4) {
+ id = this.safeString (trade, tradeLength - 4);
+ }
+ side = this.safeStringLower (trade, tradeLength - 3);
+ price = this.fromEp (this.safeFloat (trade, tradeLength - 2), market);
+ amount = this.fromEv (this.safeFloat (trade, tradeLength - 1), market);
+ if (market['spot']) {
+ if ((price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ }
+ } else {
+ timestamp = this.safeIntegerProduct (trade, 'transactTimeNs', 0.000001);
+ id = this.safeString2 (trade, 'execId', 'execID');
+ orderId = this.safeString (trade, 'orderID');
+ side = this.safeStringLower (trade, 'side');
+ type = this.parseOrderType (this.safeString (trade, 'ordType'));
+ const execStatus = this.safeString (trade, 'execStatus');
+ if (execStatus === 'MakerFill') {
+ takerOrMaker = 'maker';
+ }
+ price = this.fromEp (this.safeFloat (trade, 'execPriceEp'), market);
+ amount = this.fromEv (this.safeFloat (trade, 'execBaseQtyEv'), market);
+ amount = this.safeFloat (trade, 'execQty', amount);
+ cost = this.fromEv (this.safeFloat2 (trade, 'execQuoteQtyEv', 'execValueEv'), market);
+ const feeCost = this.fromEv (this.safeFloat (trade, 'execFeeEv'), market);
+ if (feeCost !== undefined) {
+ let feeRate = undefined;
+ let feeRateEr = this.safeFloat (trade, 'feeRateEr');
+ if (feeRateEr < 0) {
+ feeRateEr = Math.abs (feeRateEr);
+ feeRate = this.fromEr (feeRateEr, market);
+ feeRate = -feeRate;
+ } else {
+ feeRate = this.fromEr (feeRateEr, market);
+ }
+ let feeCurrencyCode = undefined;
+ if (market['spot']) {
+ feeCurrencyCode = (side === 'buy') ? market['base'] : market['quote'];
+ } else {
+ const info = this.safeValue (market, 'info');
+ if (info !== undefined) {
+ const settlementCurrencyId = this.safeString (info, 'settlementCurrency');
+ feeCurrencyCode = this.safeCurrencyCode (settlementCurrencyId);
+ }
+ }
+ fee = {
+ 'cost': feeCost,
+ 'rate': feeRate,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ }
+ return {
+ 'info': trade,
+ 'id': id,
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'order': orderId,
+ 'type': type,
+ 'side': side,
+ 'takerOrMaker': takerOrMaker,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ parseSpotBalance (response) {
+ //
+ // {
+ // "code":0,
+ // "msg":"",
+ // "data":[
+ // {
+ // "currency":"USDT",
+ // "balanceEv":0,
+ // "lockedTradingBalanceEv":0,
+ // "lockedWithdrawEv":0,
+ // "lastUpdateTimeNs":1592065834511322514,
+ // "walletVid":0
+ // },
+ // {
+ // "currency":"ETH",
+ // "balanceEv":0,
+ // "lockedTradingBalanceEv":0,
+ // "lockedWithdrawEv":0,
+ // "lastUpdateTimeNs":1592065834511322514,
+ // "walletVid":0
+ // }
+ // ]
+ // }
+ //
+ const result = { 'info': response };
+ const data = this.safeValue (response, 'data', []);
+ for (let i = 0; i < data.length; i++) {
+ const balance = data[i];
+ const currencyId = this.safeString (balance, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const currency = this.safeValue (this.currencies, code, {});
+ const scale = this.safeInteger (currency, 'valueScale', 8);
+ const account = this.account ();
+ const balanceEv = this.safeFloat (balance, 'balanceEv');
+ const lockedTradingBalanceEv = this.safeFloat (balance, 'lockedTradingBalanceEv');
+ const lockedWithdrawEv = this.safeFloat (balance, 'lockedWithdrawEv');
+ const total = this.fromEn (balanceEv, scale, scale, DECIMAL_PLACES);
+ const lockedTradingBalance = this.fromEn (lockedTradingBalanceEv, scale, scale, DECIMAL_PLACES);
+ const lockedWithdraw = this.fromEn (lockedWithdrawEv, scale, scale, DECIMAL_PLACES);
+ const used = this.sum (lockedTradingBalance, lockedWithdraw);
+ account['total'] = total;
+ account['used'] = used;
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ parseSwapBalance (response) {
+ //
+ // {
+ // "code":0,
+ // "msg":"",
+ // "data":{
+ // "account":{
+ // "accountId":6192120001,
+ // "currency":"BTC",
+ // "accountBalanceEv":1254744,
+ // "totalUsedBalanceEv":0,
+ // "bonusBalanceEv":1254744
+ // },
+ // "positions":[
+ // {
+ // "accountID":6192120001,
+ // "symbol":"BTCUSD",
+ // "currency":"BTC",
+ // "side":"None",
+ // "positionStatus":"Normal",
+ // "crossMargin":false,
+ // "leverageEr":0,
+ // "leverage":0E-8,
+ // "initMarginReqEr":1000000,
+ // "initMarginReq":0.01000000,
+ // "maintMarginReqEr":500000,
+ // "maintMarginReq":0.00500000,
+ // "riskLimitEv":10000000000,
+ // "riskLimit":100.00000000,
+ // "size":0,
+ // "value":0E-8,
+ // "valueEv":0,
+ // "avgEntryPriceEp":0,
+ // "avgEntryPrice":0E-8,
+ // "posCostEv":0,
+ // "posCost":0E-8,
+ // "assignedPosBalanceEv":0,
+ // "assignedPosBalance":0E-8,
+ // "bankruptCommEv":0,
+ // "bankruptComm":0E-8,
+ // "bankruptPriceEp":0,
+ // "bankruptPrice":0E-8,
+ // "positionMarginEv":0,
+ // "positionMargin":0E-8,
+ // "liquidationPriceEp":0,
+ // "liquidationPrice":0E-8,
+ // "deleveragePercentileEr":0,
+ // "deleveragePercentile":0E-8,
+ // "buyValueToCostEr":1150750,
+ // "buyValueToCost":0.01150750,
+ // "sellValueToCostEr":1149250,
+ // "sellValueToCost":0.01149250,
+ // "markPriceEp":96359083,
+ // "markPrice":9635.90830000,
+ // "markValueEv":0,
+ // "markValue":null,
+ // "unRealisedPosLossEv":0,
+ // "unRealisedPosLoss":null,
+ // "estimatedOrdLossEv":0,
+ // "estimatedOrdLoss":0E-8,
+ // "usedBalanceEv":0,
+ // "usedBalance":0E-8,
+ // "takeProfitEp":0,
+ // "takeProfit":null,
+ // "stopLossEp":0,
+ // "stopLoss":null,
+ // "realisedPnlEv":0,
+ // "realisedPnl":null,
+ // "cumRealisedPnlEv":0,
+ // "cumRealisedPnl":null
+ // }
+ // ]
+ // }
+ // }
+ //
+ const result = { 'info': response };
+ const data = this.safeValue (response, 'data', {});
+ const balance = this.safeValue (data, 'account', {});
+ const currencyId = this.safeString (balance, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const currency = this.currency (code);
+ const account = this.account ();
+ const accountBalanceEv = this.safeFloat (balance, 'accountBalanceEv');
+ const totalUsedBalanceEv = this.safeFloat (balance, 'totalUsedBalanceEv');
+ const valueScale = this.safeInteger (currency, 'valueScale', 8);
+ account['total'] = this.fromEn (accountBalanceEv, valueScale, valueScale, DECIMAL_PLACES);
+ account['used'] = this.fromEn (totalUsedBalanceEv, valueScale, valueScale, DECIMAL_PLACES);
+ result[code] = account;
+ return this.parseBalance (result);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const defaultType = this.safeString2 (this.options, 'defaultType', 'fetchBalance', 'spot');
+ const type = this.safeString (params, 'type', defaultType);
+ let method = 'privateGetSpotWallets';
+ const request = {};
+ if (type === 'swap') {
+ const code = this.safeString (params, 'code');
+ if (code !== undefined) {
+ const currency = this.currency (code);
+ request['currency'] = currency['id'];
+ params = this.omit (params, 'code');
+ } else {
+ const currency = this.safeString (params, 'currency');
+ if (currency === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchBalance requires a code parameter or a currency parameter for ' + type + ' type');
+ }
+ }
+ method = 'privateGetAccountsAccountPositions';
+ }
+ params = this.omit (params, 'type');
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "code":0,
+ // "msg":"",
+ // "data":[
+ // {
+ // "currency":"USDT",
+ // "balanceEv":0,
+ // "lockedTradingBalanceEv":0,
+ // "lockedWithdrawEv":0,
+ // "lastUpdateTimeNs":1592065834511322514,
+ // "walletVid":0
+ // },
+ // {
+ // "currency":"ETH",
+ // "balanceEv":0,
+ // "lockedTradingBalanceEv":0,
+ // "lockedWithdrawEv":0,
+ // "lastUpdateTimeNs":1592065834511322514,
+ // "walletVid":0
+ // }
+ // ]
+ // }
+ //
+ // swap
+ //
+ // {
+ // "code":0,
+ // "msg":"",
+ // "data":{
+ // "account":{
+ // "accountId":6192120001,
+ // "currency":"BTC",
+ // "accountBalanceEv":1254744,
+ // "totalUsedBalanceEv":0,
+ // "bonusBalanceEv":1254744
+ // },
+ // "positions":[
+ // {
+ // "accountID":6192120001,
+ // "symbol":"BTCUSD",
+ // "currency":"BTC",
+ // "side":"None",
+ // "positionStatus":"Normal",
+ // "crossMargin":false,
+ // "leverageEr":0,
+ // "leverage":0E-8,
+ // "initMarginReqEr":1000000,
+ // "initMarginReq":0.01000000,
+ // "maintMarginReqEr":500000,
+ // "maintMarginReq":0.00500000,
+ // "riskLimitEv":10000000000,
+ // "riskLimit":100.00000000,
+ // "size":0,
+ // "value":0E-8,
+ // "valueEv":0,
+ // "avgEntryPriceEp":0,
+ // "avgEntryPrice":0E-8,
+ // "posCostEv":0,
+ // "posCost":0E-8,
+ // "assignedPosBalanceEv":0,
+ // "assignedPosBalance":0E-8,
+ // "bankruptCommEv":0,
+ // "bankruptComm":0E-8,
+ // "bankruptPriceEp":0,
+ // "bankruptPrice":0E-8,
+ // "positionMarginEv":0,
+ // "positionMargin":0E-8,
+ // "liquidationPriceEp":0,
+ // "liquidationPrice":0E-8,
+ // "deleveragePercentileEr":0,
+ // "deleveragePercentile":0E-8,
+ // "buyValueToCostEr":1150750,
+ // "buyValueToCost":0.01150750,
+ // "sellValueToCostEr":1149250,
+ // "sellValueToCost":0.01149250,
+ // "markPriceEp":96359083,
+ // "markPrice":9635.90830000,
+ // "markValueEv":0,
+ // "markValue":null,
+ // "unRealisedPosLossEv":0,
+ // "unRealisedPosLoss":null,
+ // "estimatedOrdLossEv":0,
+ // "estimatedOrdLoss":0E-8,
+ // "usedBalanceEv":0,
+ // "usedBalance":0E-8,
+ // "takeProfitEp":0,
+ // "takeProfit":null,
+ // "stopLossEp":0,
+ // "stopLoss":null,
+ // "realisedPnlEv":0,
+ // "realisedPnl":null,
+ // "cumRealisedPnlEv":0,
+ // "cumRealisedPnl":null
+ // }
+ // ]
+ // }
+ // }
+ //
+ const result = (type === 'swap') ? this.parseSwapBalance (response) : this.parseSpotBalance (response);
+ return result;
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'Created': 'open',
+ 'Untriggered': 'open',
+ 'Deactivated': 'closed',
+ 'Triggered': 'open',
+ 'Rejected': 'rejected',
+ 'New': 'open',
+ 'PartiallyFilled': 'open',
+ 'Filled': 'closed',
+ 'Canceled': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrderType (type) {
+ const types = {
+ 'Limit': 'limit',
+ 'Market': 'market',
+ };
+ return this.safeString (types, type, type);
+ }
+
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'GoodTillCancel': 'GTC',
+ 'PostOnly': 'PO',
+ 'ImmediateOrCancel': 'IOC',
+ 'FillOrKill': 'FOK',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
+ }
+
+ parseSpotOrder (order, market = undefined) {
+ //
+ // spot
+ //
+ // {
+ // "orderID": "d1d09454-cabc-4a23-89a7-59d43363f16d",
+ // "clOrdID": "309bcd5c-9f6e-4a68-b775-4494542eb5cb",
+ // "priceEp": 0,
+ // "action": "New",
+ // "trigger": "UNSPECIFIED",
+ // "pegPriceType": "UNSPECIFIED",
+ // "stopDirection": "UNSPECIFIED",
+ // "bizError": 0,
+ // "symbol": "sBTCUSDT",
+ // "side": "Buy",
+ // "baseQtyEv": 0,
+ // "ordType": "Limit",
+ // "timeInForce": "GoodTillCancel",
+ // "ordStatus": "Created",
+ // "cumFeeEv": 0,
+ // "cumBaseQtyEv": 0,
+ // "cumQuoteQtyEv": 0,
+ // "leavesBaseQtyEv": 0,
+ // "leavesQuoteQtyEv": 0,
+ // "avgPriceEp": 0,
+ // "cumBaseAmountEv": 0,
+ // "cumQuoteAmountEv": 0,
+ // "quoteQtyEv": 0,
+ // "qtyType": "ByBase",
+ // "stopPxEp": 0,
+ // "pegOffsetValueEp": 0
+ // }
+ //
+ // {
+ // "orderID":"99232c3e-3d6a-455f-98cc-2061cdfe91bc",
+ // "stopPxEp":0,
+ // "avgPriceEp":0,
+ // "qtyType":"ByBase",
+ // "leavesBaseQtyEv":0,
+ // "leavesQuoteQtyEv":0,
+ // "baseQtyEv":"1000000000",
+ // "feeCurrency":"4",
+ // "stopDirection":"UNSPECIFIED",
+ // "symbol":"sETHUSDT",
+ // "side":"Buy",
+ // "quoteQtyEv":250000000000,
+ // "priceEp":25000000000,
+ // "ordType":"Limit",
+ // "timeInForce":"GoodTillCancel",
+ // "ordStatus":"Rejected",
+ // "execStatus":"NewRejected",
+ // "createTimeNs":1592675305266037130,
+ // "cumFeeEv":0,
+ // "cumBaseValueEv":0,
+ // "cumQuoteValueEv":0
+ // }
+ //
+ const id = this.safeString (order, 'orderID');
+ let clientOrderId = this.safeString (order, 'clOrdID');
+ if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
+ clientOrderId = undefined;
+ }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
+ let price = this.fromEp (this.safeFloat (order, 'priceEp'), market);
+ if (price === 0) {
+ price = undefined;
+ }
+ const amount = this.fromEv (this.safeFloat (order, 'baseQtyEv'), market);
+ const remaining = this.fromEv (this.safeFloat (order, 'leavesBaseQtyEv'), market);
+ let filled = this.fromEv (this.safeFloat (order, 'cumBaseQtyEv'), market);
+ const cost = this.fromEv (this.safeFloat (order, 'quoteQtyEv'), market);
+ const average = this.fromEp (this.safeFloat (order, 'avgPriceEp'), market);
+ const status = this.parseOrderStatus (this.safeString (order, 'ordStatus'));
+ const side = this.safeStringLower (order, 'side');
+ const type = this.parseOrderType (this.safeString (order, 'ordType'));
+ const timestamp = this.safeIntegerProduct2 (order, 'actionTimeNs', 'createTimeNs', 0.000001);
+ let fee = undefined;
+ const feeCost = this.fromEv (this.safeFloat (order, 'cumFeeEv'), market);
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': undefined,
+ };
+ }
+ if (filled === undefined) {
+ if ((amount !== undefined) && (remaining !== undefined)) {
+ filled = Math.min (0, amount - remaining);
+ }
+ }
+ const timeInForce = this.parseTimeInForce (this.safeStirng (order, 'timeInForce'));
+ const stopPrice = this.fromEp (this.safeFloat (order, 'stopPxEp', market));
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': timeInForce,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': stopPrice,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': undefined,
+ };
+ }
+
+ parseSwapOrder (order, market = undefined) {
+ //
+ // {
+ // "bizError":0,
+ // "orderID":"7a1ad384-44a3-4e54-a102-de4195a29e32",
+ // "clOrdID":"",
+ // "symbol":"ETHUSD",
+ // "side":"Buy",
+ // "actionTimeNs":1592668973945065381,
+ // "transactTimeNs":0,
+ // "orderType":"Market",
+ // "priceEp":2267500,
+ // "price":226.75000000,
+ // "orderQty":1,
+ // "displayQty":0,
+ // "timeInForce":"ImmediateOrCancel",
+ // "reduceOnly":false,
+ // "closedPnlEv":0,
+ // "closedPnl":0E-8,
+ // "closedSize":0,
+ // "cumQty":0,
+ // "cumValueEv":0,
+ // "cumValue":0E-8,
+ // "leavesQty":1,
+ // "leavesValueEv":11337,
+ // "leavesValue":1.13370000,
+ // "stopDirection":"UNSPECIFIED",
+ // "stopPxEp":0,
+ // "stopPx":0E-8,
+ // "trigger":"UNSPECIFIED",
+ // "pegOffsetValueEp":0,
+ // "execStatus":"PendingNew",
+ // "pegPriceType":"UNSPECIFIED",
+ // "ordStatus":"Created"
+ // }
+ //
+ const id = this.safeString (order, 'orderID');
+ let clientOrderId = this.safeString (order, 'clOrdID');
+ if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
+ clientOrderId = undefined;
+ }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
+ const status = this.parseOrderStatus (this.safeString (order, 'ordStatus'));
+ const side = this.safeStringLower (order, 'side');
+ const type = this.parseOrderType (this.safeString (order, 'orderType'));
+ const price = this.fromEp (this.safeFloat (order, 'priceEp'), market);
+ const amount = this.safeFloat (order, 'orderQty');
+ const filled = this.safeFloat (order, 'cumQty');
+ const remaining = this.safeFloat (order, 'leavesQty');
+ const timestamp = this.safeIntegerProduct (order, 'actionTimeNs', 0.000001);
+ const cost = this.safeFloat (order, 'cumValue');
+ let lastTradeTimestamp = this.safeIntegerProduct (order, 'transactTimeNs', 0.000001);
+ if (lastTradeTimestamp === 0) {
+ lastTradeTimestamp = undefined;
+ }
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'timeInForce'));
+ const stopPrice = this.safeFloat (order, 'stopPx');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'datetime': this.iso8601 (timestamp),
+ 'timestamp': timestamp,
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': timeInForce,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': stopPrice,
+ 'amount': amount,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'cost': cost,
+ 'average': undefined,
+ 'status': status,
+ 'fee': undefined,
+ 'trades': undefined,
+ };
+ }
+
+ parseOrder (order, market = undefined) {
+ if ('closedPnl' in order) {
+ return this.parseSwapOrder (order, market);
+ }
+ return this.parseSpotOrder (order, market);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ side = this.capitalize (side);
+ type = this.capitalize (type);
+ const request = {
+ // common
+ 'symbol': market['id'],
+ 'side': side, // Sell, Buy
+ 'ordType': type, // Market, Limit, Stop, StopLimit, MarketIfTouched, LimitIfTouched or Pegged for swap orders
+ // 'stopPxEp': this.toEp (stopPx, market), // for conditional orders
+ // 'priceEp': this.toEp (price, market), // required for limit orders
+ // 'timeInForce': 'GoodTillCancel', // GoodTillCancel, PostOnly, ImmediateOrCancel, FillOrKill
+ // ----------------------------------------------------------------
+ // spot
+ // 'qtyType': 'ByBase', // ByBase, ByQuote
+ // 'quoteQtyEv': this.toEp (cost, market),
+ // 'baseQtyEv': this.toEv (amount, market),
+ // 'trigger': 'ByLastPrice', // required for conditional orders
+ // ----------------------------------------------------------------
+ // swap
+ // 'clOrdID': this.uuid (), // max length 40
+ // 'orderQty': this.amountToPrecision (amount, symbol),
+ // 'reduceOnly': false,
+ // 'closeOnTrigger': false, // implicit reduceOnly and cancel other orders in the same direction
+ // 'takeProfitEp': this.toEp (takeProfit, market),
+ // 'stopLossEp': this.toEp (stopLossEp, market),
+ // 'triggerType': 'ByMarkPrice', // ByMarkPrice, ByLastPrice
+ // 'pegOffsetValueEp': integer, // Trailing offset from current price. Negative value when position is long, positive when position is short
+ // 'pegPriceType': 'TrailingStopPeg', // TrailingTakeProfitPeg
+ // 'text': 'comment',
+ };
+ if (market['spot']) {
+ let qtyType = this.safeValue (params, 'qtyType', 'ByBase');
+ if (price !== undefined) {
+ qtyType = 'ByQuote';
+ }
+ request['qtyType'] = qtyType;
+ if (qtyType === 'ByQuote') {
+ let cost = this.safeFloat (params, 'cost');
+ params = this.omit (params, 'cost');
+ if (this.options['createOrderByQuoteRequiresPrice']) {
+ if (price !== undefined) {
+ cost = amount * price;
+ } else if (cost === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder ' + qtyType + ' requires a price argument or a cost parameter');
+ }
+ }
+ cost = (cost === undefined) ? amount : cost;
+ request['quoteQtyEv'] = this.toEp (cost, market);
+ } else {
+ request['baseQtyEv'] = this.toEv (amount, market);
+ }
+ } else if (market['swap']) {
+ request['orderQty'] = parseInt (amount);
+ }
+ if (type === 'Limit') {
+ request['priceEp'] = this.toEp (price, market);
+ }
+ const stopPrice = this.safeFloat2 (params, 'stopPx', 'stopPrice');
+ if (stopPrice !== undefined) {
+ request['stopPxEp'] = this.toEp (stopPrice, market);
+ }
+ params = this.omit (params, [ 'stopPx', 'stopPrice' ]);
+ const method = market['spot'] ? 'privatePostSpotOrders' : 'privatePostOrders';
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "code": 0,
+ // "msg": "",
+ // "data": {
+ // "orderID": "d1d09454-cabc-4a23-89a7-59d43363f16d",
+ // "clOrdID": "309bcd5c-9f6e-4a68-b775-4494542eb5cb",
+ // "priceEp": 0,
+ // "action": "New",
+ // "trigger": "UNSPECIFIED",
+ // "pegPriceType": "UNSPECIFIED",
+ // "stopDirection": "UNSPECIFIED",
+ // "bizError": 0,
+ // "symbol": "sBTCUSDT",
+ // "side": "Buy",
+ // "baseQtyEv": 0,
+ // "ordType": "Limit",
+ // "timeInForce": "GoodTillCancel",
+ // "ordStatus": "Created",
+ // "cumFeeEv": 0,
+ // "cumBaseQtyEv": 0,
+ // "cumQuoteQtyEv": 0,
+ // "leavesBaseQtyEv": 0,
+ // "leavesQuoteQtyEv": 0,
+ // "avgPriceEp": 0,
+ // "cumBaseAmountEv": 0,
+ // "cumQuoteAmountEv": 0,
+ // "quoteQtyEv": 0,
+ // "qtyType": "ByBase",
+ // "stopPxEp": 0,
+ // "pegOffsetValueEp": 0
+ // }
+ // }
+ //
+ // swap
+ //
+ // {
+ // "code":0,
+ // "msg":"",
+ // "data":{
+ // "bizError":0,
+ // "orderID":"7a1ad384-44a3-4e54-a102-de4195a29e32",
+ // "clOrdID":"",
+ // "symbol":"ETHUSD",
+ // "side":"Buy",
+ // "actionTimeNs":1592668973945065381,
+ // "transactTimeNs":0,
+ // "orderType":"Market",
+ // "priceEp":2267500,
+ // "price":226.75000000,
+ // "orderQty":1,
+ // "displayQty":0,
+ // "timeInForce":"ImmediateOrCancel",
+ // "reduceOnly":false,
+ // "closedPnlEv":0,
+ // "closedPnl":0E-8,
+ // "closedSize":0,
+ // "cumQty":0,
+ // "cumValueEv":0,
+ // "cumValue":0E-8,
+ // "leavesQty":1,
+ // "leavesValueEv":11337,
+ // "leavesValue":1.13370000,
+ // "stopDirection":"UNSPECIFIED",
+ // "stopPxEp":0,
+ // "stopPx":0E-8,
+ // "trigger":"UNSPECIFIED",
+ // "pegOffsetValueEp":0,
+ // "execStatus":"PendingNew",
+ // "pegPriceType":"UNSPECIFIED",
+ // "ordStatus":"Created"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'clOrdID');
+ params = this.omit (params, [ 'clientOrderId', 'clOrdID' ]);
+ if (clientOrderId !== undefined) {
+ request['clOrdID'] = clientOrderId;
+ } else {
+ request['orderID'] = id;
+ }
+ const method = market['spot'] ? 'privateDeleteSpotOrders' : 'privateDeleteOrdersCancel';
+ const response = await this[method] (this.extend (request, params));
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data, market);
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'symbol': market['id'],
+ // 'untriggerred': false, // false to cancel non-conditional orders, true to cancel conditional orders
+ // 'text': 'up to 40 characters max',
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ if (!market['swap']) {
+ throw new NotSupported (this.id + ' cancelAllOrders() supports swap market type orders only');
+ }
+ request['symbol'] = market['id'];
+ }
+ return await this.privateDeleteOrdersAll (this.extend (request, params));
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const method = market['spot'] ? 'privateGetSpotOrdersActive' : 'privateGetExchangeOrder';
+ const request = {
+ 'symbol': market['id'],
+ };
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'clOrdID');
+ params = this.omit (params, [ 'clientOrderId', 'clOrdID' ]);
+ if (clientOrderId !== undefined) {
+ request['clOrdID'] = clientOrderId;
+ } else {
+ request['orderID'] = id;
+ }
+ const response = await this[method] (this.extend (request, params));
+ const data = this.safeValue (response, 'data', {});
+ let order = data;
+ if (Array.isArray (data)) {
+ const numOrders = data.length;
+ if (numOrders < 1) {
+ if (clientOrderId !== undefined) {
+ throw new OrderNotFound (this.id + ' fetchOrder ' + symbol + ' order with clientOrderId ' + clientOrderId + ' not found');
+ } else {
+ throw new OrderNotFound (this.id + ' fetchOrder ' + symbol + ' order with id ' + id + ' not found');
+ }
+ }
+ order = this.safeValue (data, 0, {});
+ }
+ return this.parseOrder (order, market);
+ }
+
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const method = market['spot'] ? 'privateGetSpotOrders' : 'privateGetExchangeOrderList';
+ const request = {
+ 'symbol': market['id'],
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this[method] (this.extend (request, params));
+ const data = this.safeValue (response, 'data', {});
+ const rows = this.safeValue (data, 'rows', []);
+ return this.parseOrders (rows, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const method = market['spot'] ? 'privateGetSpotOrders' : 'privateGetOrdersActiveList';
+ const request = {
+ 'symbol': market['id'],
+ };
+ try {
+ const response = await this[method] (this.extend (request, params));
+ const data = this.safeValue (response, 'data', {});
+ if (Array.isArray (data)) {
+ return this.parseOrders (data, market, since, limit);
+ } else {
+ const rows = this.safeValue (data, 'rows', []);
+ return this.parseOrders (rows, market, since, limit);
+ }
+ } catch (e) {
+ return [];
+ }
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchClosedOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const method = market['spot'] ? 'privateGetExchangeSpotOrder' : 'privateGetExchangeOrderList';
+ const request = {
+ 'symbol': market['id'],
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "code":0,
+ // "msg":"OK",
+ // "data":{
+ // "total":8,
+ // "rows":[
+ // {
+ // "orderID":"99232c3e-3d6a-455f-98cc-2061cdfe91bc",
+ // "stopPxEp":0,
+ // "avgPriceEp":0,
+ // "qtyType":"ByBase",
+ // "leavesBaseQtyEv":0,
+ // "leavesQuoteQtyEv":0,
+ // "baseQtyEv":"1000000000",
+ // "feeCurrency":"4",
+ // "stopDirection":"UNSPECIFIED",
+ // "symbol":"sETHUSDT",
+ // "side":"Buy",
+ // "quoteQtyEv":250000000000,
+ // "priceEp":25000000000,
+ // "ordType":"Limit",
+ // "timeInForce":"GoodTillCancel",
+ // "ordStatus":"Rejected",
+ // "execStatus":"NewRejected",
+ // "createTimeNs":1592675305266037130,
+ // "cumFeeEv":0,
+ // "cumBaseValueEv":0,
+ // "cumQuoteValueEv":0
+ // },
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ if (Array.isArray (data)) {
+ return this.parseOrders (data, market, since, limit);
+ } else {
+ const rows = this.safeValue (data, 'rows', []);
+ return this.parseOrders (rows, market, since, limit);
+ }
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchClosedOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const method = market['spot'] ? 'privateGetExchangeSpotOrderTrades' : 'privateGetExchangeOrderTrade';
+ const request = {
+ 'symbol': market['id'],
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (market['swap'] && (limit !== undefined)) {
+ request['limit'] = limit;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "code": 0,
+ // "msg": "OK",
+ // "data": {
+ // "total": 1,
+ // "rows": [
+ // {
+ // "qtyType": "ByQuote",
+ // "transactTimeNs": 1589450974800550100,
+ // "clOrdID": "8ba59d40-df25-d4b0-14cf-0703f44e9690",
+ // "orderID": "b2b7018d-f02f-4c59-b4cf-051b9c2d2e83",
+ // "symbol": "sBTCUSDT",
+ // "side": "Buy",
+ // "priceEP": 970056000000,
+ // "baseQtyEv": 0,
+ // "quoteQtyEv": 1000000000,
+ // "action": "New",
+ // "execStatus": "MakerFill",
+ // "ordStatus": "Filled",
+ // "ordType": "Limit",
+ // "execInst": "None",
+ // "timeInForce": "GoodTillCancel",
+ // "stopDirection": "UNSPECIFIED",
+ // "tradeType": "Trade",
+ // "stopPxEp": 0,
+ // "execId": "c6bd8979-07ba-5946-b07e-f8b65135dbb1",
+ // "execPriceEp": 970056000000,
+ // "execBaseQtyEv": 103000,
+ // "execQuoteQtyEv": 999157680,
+ // "leavesBaseQtyEv": 0,
+ // "leavesQuoteQtyEv": 0,
+ // "execFeeEv": 0,
+ // "feeRateEr": 0
+ // }
+ // ]
+ // }
+ // }
+ //
+ //
+ // swap
+ //
+ // {
+ // "code": 0,
+ // "msg": "OK",
+ // "data": {
+ // "total": 79,
+ // "rows": [
+ // {
+ // "transactTimeNs": 1606054879331565300,
+ // "symbol": "BTCUSD",
+ // "currency": "BTC",
+ // "action": "New",
+ // "side": "Buy",
+ // "tradeType": "Trade",
+ // "execQty": 5,
+ // "execPriceEp": 182990000,
+ // "orderQty": 5,
+ // "priceEp": 183870000,
+ // "execValueEv": 27323,
+ // "feeRateEr": 75000,
+ // "execFeeEv": 21,
+ // "ordType": "Market",
+ // "execID": "5eee56a4-04a9-5677-8eb0-c2fe22ae3645",
+ // "orderID": "ee0acb82-f712-4543-a11d-d23efca73197",
+ // "clOrdID": "",
+ // "execStatus": "TakerFill"
+ // },
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const rows = this.safeValue (data, 'rows', []);
+ return this.parseTrades (rows, market, since, limit);
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privateGetPhemexUserWalletsV2DepositAddress (this.extend (request, params));
+ // {
+ // "code":0,
+ // "msg":"OK",
+ // "data":{
+ // "address":"0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
+ // "tag":null
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const address = this.safeString (data, 'address');
+ const tag = this.safeString (data, 'tag');
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': response,
+ };
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ const response = await this.privateGetExchangeWalletsDepositList (params);
+ //
+ // {
+ // "code":0,
+ // "msg":"OK",
+ // "data":[
+ // {
+ // "id":29200,
+ // "currency":"USDT",
+ // "currencyCode":3,
+ // "txHash":"0x0bdbdc47807769a03b158d5753f54dfc58b92993d2f5e818db21863e01238e5d",
+ // "address":"0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
+ // "amountEv":3000000000,
+ // "confirmations":13,
+ // "type":"Deposit",
+ // "status":"Success",
+ // "createdAt":1592722565000
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTransactions (data, currency, since, limit);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ const response = await this.privateGetExchangeWalletsWithdrawList (params);
+ //
+ // {
+ // "code":0,
+ // "msg":"OK",
+ // "data":[
+ // {
+ // "address": "1Lxxxxxxxxxxx"
+ // "amountEv": 200000
+ // "currency": "BTC"
+ // "currencyCode": 1
+ // "expiredTime": 0
+ // "feeEv": 50000
+ // "rejectReason": null
+ // "status": "Succeed"
+ // "txHash": "44exxxxxxxxxxxxxxxxxxxxxx"
+ // "withdrawStatus: ""
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTransactions (data, currency, since, limit);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'Success': 'ok',
+ 'Succeed': 'ok',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // withdraw
+ //
+ // ...
+ //
+ // fetchDeposits
+ //
+ // {
+ // "id":29200,
+ // "currency":"USDT",
+ // "currencyCode":3,
+ // "txHash":"0x0bdbdc47807769a03b158d5753f54dfc58b92993d2f5e818db21863e01238e5d",
+ // "address":"0x5bfbf60e0fa7f63598e6cfd8a7fd3ffac4ccc6ad",
+ // "amountEv":3000000000,
+ // "confirmations":13,
+ // "type":"Deposit",
+ // "status":"Success",
+ // "createdAt":1592722565000
+ // }
+ //
+ // fetchWithdrawals
+ //
+ // {
+ // "address": "1Lxxxxxxxxxxx"
+ // "amountEv": 200000
+ // "currency": "BTC"
+ // "currencyCode": 1
+ // "expiredTime": 0
+ // "feeEv": 50000
+ // "rejectReason": null
+ // "status": "Succeed"
+ // "txHash": "44exxxxxxxxxxxxxxxxxxxxxx"
+ // "withdrawStatus: ""
+ // }
+ //
+ const id = this.safeString (transaction, 'id');
+ const address = this.safeString (transaction, 'address');
+ const tag = undefined;
+ const txid = this.safeString (transaction, 'txHash');
+ const currencyId = this.safeString (transaction, 'currency');
+ currency = this.safeCurrency (currencyId, currency);
+ const code = currency['code'];
+ const timestamp = this.safeInteger (transaction, 'createdAt');
+ let type = this.safeStringLower (transaction, 'type');
+ const feeCost = this.fromEn (this.safeFloat (transaction, 'feeEv'), currency['valueScale'], currency['precision']);
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ type = 'withdrawal';
+ fee = {
+ 'cost': feeCost,
+ 'currency': code,
+ };
+ }
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const amount = this.fromEn (this.safeFloat (transaction, 'amountEv'), currency['valueScale'], currency['precision']);
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'address': address,
+ 'addressTo': address,
+ 'addressFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'tagFrom': undefined,
+ 'type': type,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': undefined,
+ 'fee': fee,
+ };
+ }
+
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const code = this.safeString (params, 'code');
+ const request = {};
+ if (code === undefined) {
+ const currencyId = this.safeString (params, 'currency');
+ if (currencyId === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchPositions() requires a currency parameter or a code parameter');
+ }
+ } else {
+ const currency = this.currency (code);
+ params = this.omit (params, 'code');
+ request['currency'] = currency['id'];
+ }
+ const response = await this.privateGetAccountsAccountPositions (this.extend (request, params));
+ //
+ // {
+ // "code":0,"msg":"",
+ // "data":{
+ // "account":{
+ // "accountId":6192120001,
+ // "currency":"BTC",
+ // "accountBalanceEv":1254744,
+ // "totalUsedBalanceEv":0,
+ // "bonusBalanceEv":1254744
+ // },
+ // "positions":[
+ // {
+ // "accountID":6192120001,
+ // "symbol":"BTCUSD",
+ // "currency":"BTC",
+ // "side":"None",
+ // "positionStatus":"Normal",
+ // "crossMargin":false,
+ // "leverageEr":100000000,
+ // "leverage":1.00000000,
+ // "initMarginReqEr":100000000,
+ // "initMarginReq":1.00000000,
+ // "maintMarginReqEr":500000,
+ // "maintMarginReq":0.00500000,
+ // "riskLimitEv":10000000000,
+ // "riskLimit":100.00000000,
+ // "size":0,
+ // "value":0E-8,
+ // "valueEv":0,
+ // "avgEntryPriceEp":0,
+ // "avgEntryPrice":0E-8,
+ // "posCostEv":0,
+ // "posCost":0E-8,
+ // "assignedPosBalanceEv":0,
+ // "assignedPosBalance":0E-8,
+ // "bankruptCommEv":0,
+ // "bankruptComm":0E-8,
+ // "bankruptPriceEp":0,
+ // "bankruptPrice":0E-8,
+ // "positionMarginEv":0,
+ // "positionMargin":0E-8,
+ // "liquidationPriceEp":0,
+ // "liquidationPrice":0E-8,
+ // "deleveragePercentileEr":0,
+ // "deleveragePercentile":0E-8,
+ // "buyValueToCostEr":100225000,
+ // "buyValueToCost":1.00225000,
+ // "sellValueToCostEr":100075000,
+ // "sellValueToCost":1.00075000,
+ // "markPriceEp":135736070,
+ // "markPrice":13573.60700000,
+ // "markValueEv":0,
+ // "markValue":null,
+ // "unRealisedPosLossEv":0,
+ // "unRealisedPosLoss":null,
+ // "estimatedOrdLossEv":0,
+ // "estimatedOrdLoss":0E-8,
+ // "usedBalanceEv":0,
+ // "usedBalance":0E-8,
+ // "takeProfitEp":0,
+ // "takeProfit":null,
+ // "stopLossEp":0,
+ // "stopLoss":null,
+ // "cumClosedPnlEv":0,
+ // "cumFundingFeeEv":0,
+ // "cumTransactFeeEv":0,
+ // "realisedPnlEv":0,
+ // "realisedPnl":null,
+ // "cumRealisedPnlEv":0,
+ // "cumRealisedPnl":null
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const positions = this.safeValue (data, 'positions', []);
+ // todo unify parsePosition/parsePositions
+ return positions;
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const query = this.omit (params, this.extractParams (path));
+ const requestPath = '/' + this.implodeParams (path, params);
+ let url = requestPath;
+ let queryString = '';
+ if ((method === 'GET') || (method === 'DELETE') || (method === 'PUT')) {
+ if (Object.keys (query).length) {
+ queryString = this.urlencodeWithArrayRepeat (query);
+ url += '?' + queryString;
+ }
+ }
+ if (api === 'private') {
+ this.checkRequiredCredentials ();
+ const timestamp = this.seconds ();
+ const xPhemexRequestExpiry = this.safeInteger (this.options, 'x-phemex-request-expiry', 60);
+ const expiry = this.sum (timestamp, xPhemexRequestExpiry);
+ const expiryString = expiry.toString ();
+ headers = {
+ 'x-phemex-access-token': this.apiKey,
+ 'x-phemex-request-expiry': expiryString,
+ };
+ let payload = '';
+ if (method === 'POST') {
+ payload = this.json (params);
+ body = payload;
+ headers['Content-Type'] = 'application/json';
+ }
+ const auth = requestPath + queryString + expiryString + payload;
+ headers['x-phemex-request-signature'] = this.hmac (this.encode (auth), this.encode (this.secret));
+ }
+ url = this.urls['api'][api] + url;
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ //
+ // {"code":30018,"msg":"phemex.data.size.uplimt","data":null}
+ // {"code":412,"msg":"Missing parameter - resolution","data":null}
+ // {"code":412,"msg":"Missing parameter - to","data":null}
+ // {"error":{"code":6001,"message":"invalid argument"},"id":null,"result":null}
+ //
+ const error = this.safeValue (response, 'error', response);
+ const errorCode = this.safeString (error, 'code');
+ const message = this.safeString (error, 'msg');
+ if ((errorCode !== undefined) && (errorCode !== '0')) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],117:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ExchangeNotAvailable, RequestTimeout, AuthenticationError, PermissionDenied, DDoSProtection, InsufficientFunds, OrderNotFound, OrderNotCached, InvalidOrder, AccountSuspended, CancelPending, InvalidNonce, OnMaintenance } = require ('./base/errors');
+const { ExchangeError, ExchangeNotAvailable, RequestTimeout, AuthenticationError, PermissionDenied, DDoSProtection, InsufficientFunds, OrderNotFound, InvalidOrder, AccountSuspended, CancelPending, InvalidNonce, OnMaintenance, BadSymbol } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -80796,27 +96661,30 @@ module.exports = class poloniex extends Exchange {
'name': 'Poloniex',
'countries': [ 'US' ],
'rateLimit': 1000, // up to 6 calls per second
- 'certified': true, // 2019-06-07
+ 'certified': false,
'pro': true,
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createDepositAddress': true,
'createMarketOrder': false,
+ 'createOrder': true,
'editOrder': true,
- 'fetchClosedOrders': 'emulated',
+ 'fetchBalance': true,
'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrder': true, // true endpoint for a single open order
'fetchOpenOrders': true, // true endpoint for open orders
- 'fetchOrder': 'emulated', // no endpoint for a single open-or-closed order (just for an open order only)
+ 'fetchOrderBook': true,
'fetchOrderBooks': true,
- 'fetchOrders': 'emulated', // no endpoint for open-or-closed orders (just for open orders only)
- 'fetchOrderStatus': 'emulated', // no endpoint for status of a single open-or-closed order (just for open orders only)
'fetchOrderTrades': true, // true endpoint for trades of a single open or closed order
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
'fetchTransactions': true,
@@ -80841,7 +96709,7 @@ module.exports = class poloniex extends Exchange {
'www': 'https://www.poloniex.com',
'doc': 'https://docs.poloniex.com',
'fees': 'https://poloniex.com/fees',
- 'referral': 'https://www.poloniex.com/?utm_source=ccxt&utm_medium=web',
+ 'referral': 'https://poloniex.com/signup?c=UBFZJRPJ',
},
'api': {
'public': {
@@ -80927,11 +96795,23 @@ module.exports = class poloniex extends Exchange {
'GPUC': 'GPU',
'HOT': 'Hotcoin',
'ITC': 'Information Coin',
- 'PLX': 'ParallaxCoin',
'KEY': 'KEYCoin',
+ 'PLX': 'ParallaxCoin',
+ 'REPV2': 'REP',
'STR': 'XLM',
'SOC': 'SOCC',
'XAP': 'API Coin',
+ // this is not documented in the API docs for Poloniex
+ // https://github.com/ccxt/ccxt/issues/7084
+ // when the user calls withdraw ('USDT', amount, address, tag, params)
+ // with params = { 'currencyToWithdrawAs': 'USDTTRON' }
+ // or params = { 'currencyToWithdrawAs': 'USDTETH' }
+ // fetchWithdrawals ('USDT') returns the corresponding withdrawals
+ // with a USDTTRON or a USDTETH currency id, respectfully
+ // therefore we have map them back to the original code USDT
+ // otherwise the returned withdrawals are filtered out
+ 'USDTTRON': 'USDT',
+ 'USDTETH': 'USDT',
},
'options': {
'limits': {
@@ -80957,6 +96837,8 @@ module.exports = class poloniex extends Exchange {
'Invalid API key/secret pair.': AuthenticationError,
'Please do not make more than 8 API calls per second.': DDoSProtection,
'Rate must be greater than zero.': InvalidOrder, // {"error":"Rate must be greater than zero."}
+ 'Invalid currency pair.': BadSymbol, // {"error":"Invalid currency pair."}
+ 'Invalid currencyPair parameter.': BadSymbol, // {"error":"Invalid currencyPair parameter."}
},
'broad': {
'Total must be at least': InvalidOrder, // {"error":"Total must be at least 0.0001."}
@@ -80966,8 +96848,10 @@ module.exports = class poloniex extends Exchange {
'You have already called cancelOrder or moveOrder on this order.': CancelPending,
'Amount must be at least': InvalidOrder, // {"error":"Amount must be at least 0.000001."}
'is either completed or does not exist': InvalidOrder, // {"error":"Order 587957810791 is either completed or does not exist."}
+ 'Error pulling ': ExchangeError, // {"error":"Error pulling order book"}
},
},
+ 'orders': {}, // orders cache / emulation
});
}
@@ -80989,7 +96873,19 @@ module.exports = class poloniex extends Exchange {
};
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "date":1590913773,
+ // "high":0.02491611,
+ // "low":0.02491611,
+ // "open":0.02491611,
+ // "close":0.02491611,
+ // "volume":0,
+ // "quoteVolume":0,
+ // "weightedAverage":0.02491611
+ // }
+ //
return [
this.safeTimestamp (ohlcv, 'date'),
this.safeFloat (ohlcv, 'open'),
@@ -81022,9 +96918,25 @@ module.exports = class poloniex extends Exchange {
}
}
const response = await this.publicGetReturnChartData (this.extend (request, params));
+ //
+ // [
+ // {"date":1590913773,"high":0.02491611,"low":0.02491611,"open":0.02491611,"close":0.02491611,"volume":0,"quoteVolume":0,"weightedAverage":0.02491611},
+ // {"date":1590913800,"high":0.02495324,"low":0.02489501,"open":0.02491797,"close":0.02493693,"volume":0.0927415,"quoteVolume":3.7227869,"weightedAverage":0.02491185},
+ // {"date":1590914100,"high":0.02498596,"low":0.02488503,"open":0.02493033,"close":0.02497896,"volume":0.21196348,"quoteVolume":8.50291888,"weightedAverage":0.02492832},
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
+ async loadMarkets (reload = false, params = {}) {
+ const markets = await super.loadMarkets (reload, params);
+ const currenciesByNumericId = this.safeValue (this.options, 'currenciesByNumericId');
+ if ((currenciesByNumericId === undefined) || reload) {
+ this.options['currenciesByNumericId'] = this.indexBy (this.currencies, 'numericId');
+ }
+ return markets;
+ }
+
async fetchMarkets (params = {}) {
const markets = await this.publicGetReturnTicker (params);
const keys = Object.keys (markets);
@@ -81083,6 +96995,16 @@ module.exports = class poloniex extends Exchange {
async fetchTradingFees (params = {}) {
await this.loadMarkets ();
const fees = await this.privatePostReturnFeeInfo (params);
+ //
+ // {
+ // makerFee: '0.00100000',
+ // takerFee: '0.00200000',
+ // marginMakerFee: '0.00100000',
+ // marginTakerFee: '0.00200000',
+ // thirtyDayVolume: '106.08463302',
+ // nextTier: 500000,
+ // }
+ //
return {
'info': fees,
'maker': this.safeFloat (fees, 'makerFee'),
@@ -81197,7 +97119,7 @@ module.exports = class poloniex extends Exchange {
const ticker = response[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchCurrencies (params = {}) {
@@ -81211,6 +97133,7 @@ module.exports = class poloniex extends Exchange {
const code = this.safeCurrencyCode (id);
const active = (currency['delisted'] === 0) && !currency['disabled'];
const numericId = this.safeInteger (currency, 'id');
+ const fee = this.safeFloat (currency, 'txFee');
result[code] = {
'id': id,
'numericId': numericId,
@@ -81218,7 +97141,7 @@ module.exports = class poloniex extends Exchange {
'info': currency,
'name': currency['name'],
'active': active,
- 'fee': this.safeFloat (currency, 'txFee'), // todo: redesign
+ 'fee': fee,
'precision': precision,
'limits': {
'amount': {
@@ -81234,7 +97157,7 @@ module.exports = class poloniex extends Exchange {
'max': undefined,
},
'withdraw': {
- 'min': currency['txFee'],
+ 'min': fee,
'max': Math.pow (10, precision),
},
},
@@ -81253,31 +97176,20 @@ module.exports = class poloniex extends Exchange {
parseTrade (trade, market = undefined) {
//
- // fetchMyTrades (symbol defined, specific market)
+ // fetchMyTrades
//
// {
- // globalTradeID: 394698946,
- // tradeID: 45210255,
- // date: '2018-10-23 17:28:55',
- // type: 'sell',
- // rate: '0.03114126',
- // amount: '0.00018753',
- // total: '0.00000583'
- // }
- //
- // fetchMyTrades (symbol undefined, all markets)
- //
- // {
- // globalTradeID: 394131412,
- // tradeID: '5455033',
- // date: '2018-10-16 18:05:17',
- // rate: '0.06935244',
- // amount: '1.40308443',
- // total: '0.09730732',
- // fee: '0.00100000',
- // orderNumber: '104768235081',
- // type: 'sell',
- // category: 'exchange'
+ // globalTradeID: 471030550,
+ // tradeID: '42582',
+ // date: '2020-06-16 09:47:50',
+ // rate: '0.000079980000',
+ // amount: '75215.00000000',
+ // total: '6.01569570',
+ // fee: '0.00095000',
+ // feeDisplay: '0.26636100 TRX (0.07125%)',
+ // orderNumber: '5963454848',
+ // type: 'sell',
+ // category: 'exchange'
// }
//
// createOrder (taker trades)
@@ -81296,48 +97208,45 @@ module.exports = class poloniex extends Exchange {
const orderId = this.safeString (trade, 'orderNumber');
const timestamp = this.parse8601 (this.safeString (trade, 'date'));
let symbol = undefined;
- let base = undefined;
- let quote = undefined;
if ((!market) && ('currencyPair' in trade)) {
- const currencyPair = trade['currencyPair'];
- if (currencyPair in this.markets_by_id) {
- market = this.markets_by_id[currencyPair];
+ const marketId = this.safeString (trade, 'currencyPair');
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
} else {
- const parts = currencyPair.split ('_');
- quote = parts[0];
- base = parts[1];
+ const [ quoteId, baseId ] = marketId.split ('_');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
symbol = base + '/' + quote;
}
}
- if (market !== undefined) {
+ if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
- base = market['base'];
- quote = market['quote'];
}
const side = this.safeString (trade, 'type');
let fee = undefined;
const price = this.safeFloat (trade, 'rate');
const cost = this.safeFloat (trade, 'total');
const amount = this.safeFloat (trade, 'amount');
- if ('fee' in trade) {
- const rate = this.safeFloat (trade, 'fee');
- let feeCost = undefined;
- let currency = undefined;
- if (side === 'buy') {
- currency = base;
- feeCost = amount * rate;
- } else {
- currency = quote;
- if (cost !== undefined) {
- feeCost = cost * rate;
+ const feeDisplay = this.safeString (trade, 'feeDisplay');
+ if (feeDisplay !== undefined) {
+ const parts = feeDisplay.split (' ');
+ const feeCost = this.safeFloat (parts, 0);
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (parts, 1);
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ let feeRate = this.safeString (parts, 2);
+ if (feeRate !== undefined) {
+ feeRate = feeRate.replace ('(', '');
+ const feeRateParts = feeRate.split ('%');
+ feeRate = this.safeString (feeRateParts, 0);
+ feeRate = parseFloat (feeRate) / 100;
}
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ 'rate': feeRate,
+ };
}
- fee = {
- 'type': undefined,
- 'rate': rate,
- 'cost': feeCost,
- 'currency': currency,
- };
}
let takerOrMaker = undefined;
const takerAdjustment = this.safeFloat (trade, 'takerAdjustment');
@@ -81397,49 +97306,59 @@ module.exports = class poloniex extends Exchange {
//
// [
// {
- // globalTradeID: 394700861,
- // tradeID: 45210354,
- // date: '2018-10-23 18:01:58',
- // type: 'buy',
- // rate: '0.03117266',
- // amount: '0.00000652',
- // total: '0.00000020'
+ // globalTradeID: 470912587,
+ // tradeID: '42543',
+ // date: '2020-06-15 17:31:22',
+ // rate: '0.000083840000',
+ // amount: '95237.60321429',
+ // total: '7.98472065',
+ // fee: '0.00095000',
+ // feeDisplay: '0.36137761 TRX (0.07125%)',
+ // orderNumber: '5926344995',
+ // type: 'sell',
+ // category: 'exchange'
// },
// {
- // globalTradeID: 394698946,
- // tradeID: 45210255,
- // date: '2018-10-23 17:28:55',
+ // globalTradeID: 470974497,
+ // tradeID: '42560',
+ // date: '2020-06-16 00:41:23',
+ // rate: '0.000078220000',
+ // amount: '1000000.00000000',
+ // total: '78.22000000',
+ // fee: '0.00095000',
+ // feeDisplay: '3.48189819 TRX (0.07125%)',
+ // orderNumber: '5945490830',
// type: 'sell',
- // rate: '0.03114126',
- // amount: '0.00018753',
- // total: '0.00000583'
+ // category: 'exchange'
// }
// ]
//
// all markets (symbol undefined)
//
// {
- // BTC_BCH: [{
- // globalTradeID: 394131412,
- // tradeID: '5455033',
- // date: '2018-10-16 18:05:17',
- // rate: '0.06935244',
- // amount: '1.40308443',
- // total: '0.09730732',
- // fee: '0.00100000',
- // orderNumber: '104768235081',
- // type: 'sell',
+ // BTC_GNT: [{
+ // globalTradeID: 470839947,
+ // tradeID: '4322347',
+ // date: '2020-06-15 12:25:24',
+ // rate: '0.000005810000',
+ // amount: '1702.04429303',
+ // total: '0.00988887',
+ // fee: '0.00095000',
+ // feeDisplay: '4.18235294 TRX (0.07125%)',
+ // orderNumber: '102290272520',
+ // type: 'buy',
// category: 'exchange'
- // }, {
- // globalTradeID: 394126818,
- // tradeID: '5455007',
- // date: '2018-10-16 16:55:34',
- // rate: '0.06935244',
- // amount: '0.00155709',
- // total: '0.00010798',
- // fee: '0.00200000',
- // orderNumber: '104768179137',
- // type: 'sell',
+ // }, {
+ // globalTradeID: 470895902,
+ // tradeID: '4322413',
+ // date: '2020-06-15 16:19:00',
+ // rate: '0.000005980000',
+ // amount: '18.66879219',
+ // total: '0.00011163',
+ // fee: '0.00095000',
+ // feeDisplay: '0.04733727 TRX (0.07125%)',
+ // orderNumber: '102298304480',
+ // type: 'buy',
// category: 'exchange'
// }],
// }
@@ -81542,22 +97461,40 @@ module.exports = class poloniex extends Exchange {
// 'side': side,
// 'price': price,
// 'amount': amount,
+ // // ---------------------------------------------------------
+ // // 'resultingTrades' in editOrder
+ // 'resultingTrades': {
+ // 'BTC_MANA': [],
+ // }
// }
//
let timestamp = this.safeInteger (order, 'timestamp');
- if (!timestamp) {
- timestamp = this.parse8601 (order['date']);
- }
- let trades = undefined;
- if ('resultingTrades' in order) {
- trades = this.parseTrades (order['resultingTrades'], market);
+ if (timestamp === undefined) {
+ timestamp = this.parse8601 (this.safeString (order, 'date'));
}
let symbol = undefined;
const marketId = this.safeString (order, 'currencyPair');
- market = this.safeValue (this.markets_by_id, marketId, market);
- if (market !== undefined) {
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const [ quoteId, baseId ] = marketId.split ('_');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
+ let trades = undefined;
+ let resultingTrades = this.safeValue (order, 'resultingTrades');
+ if (!Array.isArray (resultingTrades)) {
+ resultingTrades = this.safeValue (resultingTrades, this.safeString (market, 'id', marketId));
+ }
+ if (resultingTrades !== undefined) {
+ trades = this.parseTrades (resultingTrades, market);
+ }
const price = this.safeFloat2 (order, 'price', 'rate');
let remaining = this.safeFloat (order, 'amount');
let amount = this.safeFloat (order, 'startingAmount');
@@ -81592,9 +97529,11 @@ module.exports = class poloniex extends Exchange {
lastTradeTimestamp = Math.max (lastTradeTimestamp, trade['timestamp']);
}
}
- remaining = Math.max (amount - filled, 0);
- if (filled >= amount) {
- status = 'closed';
+ if (amount !== undefined) {
+ remaining = Math.max (amount - filled, 0);
+ if (filled >= amount) {
+ status = 'closed';
+ }
}
}
}
@@ -81630,8 +97569,10 @@ module.exports = class poloniex extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -81656,7 +97597,7 @@ module.exports = class poloniex extends Exchange {
return result;
}
- async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
let market = undefined;
if (symbol !== undefined) {
@@ -81667,93 +97608,25 @@ module.exports = class poloniex extends Exchange {
'currencyPair': pair,
};
const response = await this.privatePostReturnOpenOrders (this.extend (request, params));
- let openOrders = [];
- if (market !== undefined) {
- openOrders = this.parseOpenOrders (response, market, openOrders);
- } else {
+ const extension = { 'status': 'open' };
+ if (market === undefined) {
const marketIds = Object.keys (response);
+ let openOrders = [];
for (let i = 0; i < marketIds.length; i++) {
const marketId = marketIds[i];
const orders = response[marketId];
const m = this.markets_by_id[marketId];
- openOrders = this.parseOpenOrders (orders, m, openOrders);
+ openOrders = this.arrayConcat (openOrders, this.parseOrders (orders, m, undefined, undefined, extension));
}
+ return this.filterBySinceLimit (openOrders, since, limit);
+ } else {
+ return this.parseOrders (response, market, since, limit, extension);
}
- for (let j = 0; j < openOrders.length; j++) {
- this.orders[openOrders[j]['id']] = openOrders[j];
- }
- const openOrdersIndexedById = this.indexBy (openOrders, 'id');
- const cachedOrderIds = Object.keys (this.orders);
- const result = [];
- for (let k = 0; k < cachedOrderIds.length; k++) {
- const id = cachedOrderIds[k];
- if (id in openOrdersIndexedById) {
- this.orders[id] = this.extend (this.orders[id], openOrdersIndexedById[id]);
- } else {
- let order = this.orders[id];
- if (order['status'] === 'open') {
- order = this.extend (order, {
- 'status': 'closed',
- 'cost': undefined,
- 'filled': order['amount'],
- 'remaining': 0.0,
- });
- if (order['cost'] === undefined) {
- if (order['filled'] !== undefined) {
- order['cost'] = order['filled'] * order['price'];
- }
- }
- this.orders[id] = order;
- }
- }
- const order = this.orders[id];
- if (market !== undefined) {
- if (order['symbol'] === symbol) {
- result.push (order);
- }
- } else {
- result.push (order);
- }
- }
- return this.filterBySinceLimit (result, since, limit);
- }
-
- async fetchOrder (id, symbol = undefined, params = {}) {
- const since = this.safeValue (params, 'since');
- const limit = this.safeValue (params, 'limit');
- const request = this.omit (params, [ 'since', 'limit' ]);
- const orders = await this.fetchOrders (symbol, since, limit, request);
- for (let i = 0; i < orders.length; i++) {
- if (orders[i]['id'] === id) {
- return orders[i];
- }
- }
- throw new OrderNotCached (this.id + ' order id ' + id.toString () + ' is not in "open" state and not found in cache');
- }
-
- filterOrdersByStatus (orders, status) {
- const result = [];
- for (let i = 0; i < orders.length; i++) {
- if (orders[i]['status'] === status) {
- result.push (orders[i]);
- }
- }
- return result;
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const orders = await this.fetchOrders (symbol, since, limit, params);
- return this.filterOrdersByStatus (orders, 'open');
- }
-
- async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const orders = await this.fetchOrders (symbol, since, limit, params);
- return this.filterOrdersByStatus (orders, 'closed');
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- if (type !== 'limit') {
- throw new ExchangeError (this.id + ' allows limit orders only');
+ if (type === 'market') {
+ throw new ExchangeError (this.id + ' createOrder() does not accept market orders');
}
await this.loadMarkets ();
const method = 'privatePost' + this.capitalize (side);
@@ -81764,6 +97637,11 @@ module.exports = class poloniex extends Exchange {
'rate': this.priceToPrecision (symbol, price),
'amount': amount,
};
+ const clientOrderId = this.safeString (params, 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['clientOrderId'] = clientOrderId;
+ params = this.omit (params, 'clientOrderId');
+ }
// remember the timestamp before issuing the request
const timestamp = this.milliseconds ();
const response = await this[method] (this.extend (request, params));
@@ -81785,7 +97663,7 @@ module.exports = class poloniex extends Exchange {
// 'currencyPair': 'BTC_MANA',
// }
//
- const order = this.parseOrder (this.extend ({
+ return this.parseOrder (this.extend ({
'timestamp': timestamp,
'status': 'open',
'type': type,
@@ -81793,9 +97671,6 @@ module.exports = class poloniex extends Exchange {
'price': price,
'amount': amount,
}, response), market);
- const id = order['id'];
- this.orders[id] = order;
- return this.extend ({ 'info': response }, order);
}
async editOrder (id, symbol, type, side, amount, price = undefined, params = {}) {
@@ -81809,59 +97684,20 @@ module.exports = class poloniex extends Exchange {
request['amount'] = this.amountToPrecision (symbol, amount);
}
const response = await this.privatePostMoveOrder (this.extend (request, params));
- let result = undefined;
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- const newid = response['orderNumber'];
- this.orders[newid] = this.extend (this.orders[id], {
- 'id': newid,
- 'price': price,
- 'status': 'open',
- });
- if (amount !== undefined) {
- this.orders[newid]['amount'] = amount;
- }
- result = this.extend (this.orders[newid], { 'info': response });
- } else {
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- }
- result = this.parseOrder (response, market);
- this.orders[result['id']] = result;
- }
- return result;
+ return this.parseOrder (response);
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- let response = undefined;
- try {
- response = await this.privatePostCancelOrder (this.extend ({
- 'orderNumber': id,
- }, params));
- } catch (e) {
- if (e instanceof CancelPending) {
- // A request to cancel the order has been sent already.
- // If we then attempt to cancel the order the second time
- // before the first request is processed the exchange will
- // throw a CancelPending exception. Poloniex won't show the
- // order in the list of active (open) orders and the cached
- // order will be marked as 'closed' (see #1801 for details).
- // To avoid that we proactively mark the order as 'canceled'
- // here. If for some reason the order does not get canceled
- // and still appears in the active list then the order cache
- // will eventually get back in sync on a call to `fetchOrder`.
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- }
- }
- throw e;
+ const request = {};
+ const clientOrderId = this.safeValue (params, 'clientOrderId');
+ if (clientOrderId === undefined) {
+ request['orderNumber'] = id;
+ } else {
+ request['clientOrderId'] = clientOrderId;
}
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- }
- return response;
+ params = this.omit (params, 'clientOrderId');
+ return await this.privatePostCancelOrder (this.extend (request, params));
}
async cancelAllOrders (symbol = undefined, params = {}) {
@@ -81884,22 +97720,16 @@ module.exports = class poloniex extends Exchange {
// ]
// }
//
- const orderIds = this.safeValue (response, 'orderNumbers', []);
- for (let i = 0; i < orderIds.length; i++) {
- const id = orderIds[i].toString ();
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- }
- }
return response;
}
async fetchOpenOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
id = id.toString ();
- const response = await this.privatePostReturnOrderStatus (this.extend ({
+ const request = {
'orderNumber': id,
- }, params));
+ };
+ const response = await this.privatePostReturnOrderStatus (this.extend (request, params));
//
// {
// success: 1,
@@ -81921,10 +97751,7 @@ module.exports = class poloniex extends Exchange {
if (result === undefined) {
throw new OrderNotFound (this.id + ' order id ' + id + ' not found');
}
- const order = this.parseOrder (result);
- order['id'] = id;
- this.orders[id] = order;
- return order;
+ return this.parseOrder (result);
}
async fetchOrderStatus (id, symbol = undefined, params = {}) {
@@ -81945,9 +97772,17 @@ module.exports = class poloniex extends Exchange {
async createDepositAddress (code, params = {}) {
await this.loadMarkets ();
- const currency = this.currency (code);
+ // USDT, USDTETH, USDTTRON
+ let currencyId = undefined;
+ let currency = undefined;
+ if (code in this.currencies) {
+ currency = this.currency (code);
+ currencyId = currency['id'];
+ } else {
+ currencyId = code;
+ }
const request = {
- 'currency': currency['id'],
+ 'currency': currencyId,
};
const response = await this.privatePostGenerateNewAddress (this.extend (request, params));
let address = undefined;
@@ -81956,10 +97791,12 @@ module.exports = class poloniex extends Exchange {
address = this.safeString (response, 'response');
}
this.checkAddress (address);
- const depositAddress = this.safeString (currency['info'], 'depositAddress');
- if (depositAddress !== undefined) {
- tag = address;
- address = depositAddress;
+ if (currency !== undefined) {
+ const depositAddress = this.safeString (currency['info'], 'depositAddress');
+ if (depositAddress !== undefined) {
+ tag = address;
+ address = depositAddress;
+ }
}
return {
'currency': code,
@@ -81971,16 +97808,25 @@ module.exports = class poloniex extends Exchange {
async fetchDepositAddress (code, params = {}) {
await this.loadMarkets ();
- const currency = this.currency (code);
const response = await this.privatePostReturnDepositAddresses (params);
- const currencyId = currency['id'];
+ // USDT, USDTETH, USDTTRON
+ let currencyId = undefined;
+ let currency = undefined;
+ if (code in this.currencies) {
+ currency = this.currency (code);
+ currencyId = currency['id'];
+ } else {
+ currencyId = code;
+ }
let address = this.safeString (response, currencyId);
let tag = undefined;
this.checkAddress (address);
- const depositAddress = this.safeString (currency['info'], 'depositAddress');
- if (depositAddress !== undefined) {
- tag = address;
- address = depositAddress;
+ if (currency !== undefined) {
+ const depositAddress = this.safeString (currency['info'], 'depositAddress');
+ if (depositAddress !== undefined) {
+ tag = address;
+ address = depositAddress;
+ }
}
return {
'currency': code,
@@ -81999,10 +97845,17 @@ module.exports = class poloniex extends Exchange {
'amount': amount,
'address': address,
};
- if (tag) {
+ if (tag !== undefined) {
request['paymentId'] = tag;
}
const response = await this.privatePostWithdraw (this.extend (request, params));
+ //
+ // {
+ // response: 'Withdrew 1.00000000 USDT.',
+ // email2FA: false,
+ // withdrawalNumber: 13449869
+ // }
+ //
return {
'info': response,
'id': this.safeString (response, 'withdrawalNumber'),
@@ -82023,44 +97876,75 @@ module.exports = class poloniex extends Exchange {
}
const response = await this.privatePostReturnDepositsWithdrawals (this.extend (request, params));
//
- // { deposits: [ { currency: "BTC",
- // address: "1MEtiqJWru53FhhHrfJPPvd2tC3TPDVcmW",
- // amount: "0.01063000",
- // confirmations: 1,
- // txid: "952b0e1888d6d491591facc0d37b5ebec540ac1efb241fdbc22bcc20d1822fb6",
- // timestamp: 1507916888,
- // status: "COMPLETE" },
- // { currency: "ETH",
- // address: "0x20108ba20b65c04d82909e91df06618107460197",
- // amount: "4.00000000",
- // confirmations: 38,
- // txid: "0x4be260073491fe63935e9e0da42bd71138fdeb803732f41501015a2d46eb479d",
- // timestamp: 1525060430,
- // status: "COMPLETE" } ],
- // withdrawals: [ { withdrawalNumber: 8224394,
- // currency: "EMC2",
- // address: "EYEKyCrqTNmVCpdDV8w49XvSKRP9N3EUyF",
- // amount: "63.10796020",
- // fee: "0.01000000",
- // timestamp: 1510819838,
- // status: "COMPLETE: d37354f9d02cb24d98c8c4fc17aa42f475530b5727effdf668ee5a43ce667fd6",
- // ipAddress: "5.220.220.200" },
- // { withdrawalNumber: 9290444,
- // currency: "ETH",
- // address: "0x191015ff2e75261d50433fbd05bd57e942336149",
- // amount: "0.15500000",
- // fee: "0.00500000",
- // timestamp: 1514099289,
- // status: "COMPLETE: 0x12d444493b4bca668992021fd9e54b5292b8e71d9927af1f076f554e4bea5b2d",
- // ipAddress: "5.228.227.214" },
- // { withdrawalNumber: 11518260,
- // currency: "BTC",
- // address: "8JoDXAmE1GY2LRK8jD1gmAmgRPq54kXJ4t",
- // amount: "0.20000000",
- // fee: "0.00050000",
- // timestamp: 1527918155,
- // status: "COMPLETE: 1864f4ebb277d90b0b1ff53259b36b97fa1990edc7ad2be47c5e0ab41916b5ff",
- // ipAddress: "211.8.195.26" } ] }
+ // {
+ // "adjustments":[],
+ // "deposits":[
+ // {
+ // currency: "BTC",
+ // address: "1MEtiqJWru53FhhHrfJPPvd2tC3TPDVcmW",
+ // amount: "0.01063000",
+ // confirmations: 1,
+ // txid: "952b0e1888d6d491591facc0d37b5ebec540ac1efb241fdbc22bcc20d1822fb6",
+ // timestamp: 1507916888,
+ // status: "COMPLETE"
+ // },
+ // {
+ // currency: "ETH",
+ // address: "0x20108ba20b65c04d82909e91df06618107460197",
+ // amount: "4.00000000",
+ // confirmations: 38,
+ // txid: "0x4be260073491fe63935e9e0da42bd71138fdeb803732f41501015a2d46eb479d",
+ // timestamp: 1525060430,
+ // status: "COMPLETE"
+ // }
+ // ],
+ // "withdrawals":[
+ // {
+ // "withdrawalNumber":13449869,
+ // "currency":"USDTTRON", // not documented in API docs, see commonCurrencies in describe()
+ // "address":"TXGaqPW23JdRWhsVwS2mRsGsegbdnAd3Rw",
+ // "amount":"1.00000000",
+ // "fee":"0.00000000",
+ // "timestamp":1591573420,
+ // "status":"COMPLETE: dadf427224b3d44b38a2c13caa4395e4666152556ca0b2f67dbd86a95655150f",
+ // "ipAddress":"74.116.3.247",
+ // "canCancel":0,
+ // "canResendEmail":0,
+ // "paymentID":null,
+ // "scope":"crypto"
+ // },
+ // {
+ // withdrawalNumber: 8224394,
+ // currency: "EMC2",
+ // address: "EYEKyCrqTNmVCpdDV8w49XvSKRP9N3EUyF",
+ // amount: "63.10796020",
+ // fee: "0.01000000",
+ // timestamp: 1510819838,
+ // status: "COMPLETE: d37354f9d02cb24d98c8c4fc17aa42f475530b5727effdf668ee5a43ce667fd6",
+ // ipAddress: "5.220.220.200"
+ // },
+ // {
+ // withdrawalNumber: 9290444,
+ // currency: "ETH",
+ // address: "0x191015ff2e75261d50433fbd05bd57e942336149",
+ // amount: "0.15500000",
+ // fee: "0.00500000",
+ // timestamp: 1514099289,
+ // status: "COMPLETE: 0x12d444493b4bca668992021fd9e54b5292b8e71d9927af1f076f554e4bea5b2d",
+ // ipAddress: "5.228.227.214"
+ // },
+ // {
+ // withdrawalNumber: 11518260,
+ // currency: "BTC",
+ // address: "8JoDXAmE1GY2LRK8jD1gmAmgRPq54kXJ4t",
+ // amount: "0.20000000",
+ // fee: "0.00050000",
+ // timestamp: 1527918155,
+ // status: "COMPLETE: 1864f4ebb277d90b0b1ff53259b36b97fa1990edc7ad2be47c5e0ab41916b5ff",
+ // ipAddress: "211.8.195.26"
+ // }
+ // ]
+ // }
//
return response;
}
@@ -82068,46 +97952,38 @@ module.exports = class poloniex extends Exchange {
async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.fetchTransactionsHelper (code, since, limit, params);
- for (let i = 0; i < response['deposits'].length; i++) {
- response['deposits'][i]['type'] = 'deposit';
- }
- for (let i = 0; i < response['withdrawals'].length; i++) {
- response['withdrawals'][i]['type'] = 'withdrawal';
- }
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
}
- const withdrawals = this.parseTransactions (response['withdrawals'], currency, since, limit);
- const deposits = this.parseTransactions (response['deposits'], currency, since, limit);
- const transactions = this.arrayConcat (deposits, withdrawals);
+ const withdrawals = this.safeValue (response, 'withdrawals', []);
+ const deposits = this.safeValue (response, 'deposits', []);
+ const withdrawalTransactions = this.parseTransactions (withdrawals, currency, since, limit);
+ const depositTransactions = this.parseTransactions (deposits, currency, since, limit);
+ const transactions = this.arrayConcat (depositTransactions, withdrawalTransactions);
return this.filterByCurrencySinceLimit (this.sortBy (transactions, 'timestamp'), code, since, limit);
}
async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
const response = await this.fetchTransactionsHelper (code, since, limit, params);
- for (let i = 0; i < response['withdrawals'].length; i++) {
- response['withdrawals'][i]['type'] = 'withdrawal';
- }
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
}
- const withdrawals = this.parseTransactions (response['withdrawals'], currency, since, limit);
- return this.filterByCurrencySinceLimit (withdrawals, code, since, limit);
+ const withdrawals = this.safeValue (response, 'withdrawals', []);
+ const transactions = this.parseTransactions (withdrawals, currency, since, limit);
+ return this.filterByCurrencySinceLimit (transactions, code, since, limit);
}
async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
const response = await this.fetchTransactionsHelper (code, since, limit, params);
- for (let i = 0; i < response['deposits'].length; i++) {
- response['deposits'][i]['type'] = 'deposit';
- }
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
}
- const deposits = this.parseTransactions (response['deposits'], currency, since, limit);
- return this.filterByCurrencySinceLimit (deposits, code, since, limit);
+ const deposits = this.safeValue (response, 'deposits', []);
+ const transactions = this.parseTransactions (deposits, currency, since, limit);
+ return this.filterByCurrencySinceLimit (transactions, code, since, limit);
}
parseTransactionStatus (status) {
@@ -82164,15 +98040,14 @@ module.exports = class poloniex extends Exchange {
}
status = this.parseTransactionStatus (status);
}
- const type = this.safeString (transaction, 'type');
+ const defaultType = ('withdrawalNumber' in transaction) ? 'withdrawal' : 'deposit';
+ const type = this.safeString (transaction, 'type', defaultType);
const id = this.safeString2 (transaction, 'withdrawalNumber', 'depositNumber');
let amount = this.safeFloat (transaction, 'amount');
const address = this.safeString (transaction, 'address');
- let feeCost = this.safeFloat (transaction, 'fee');
- if (feeCost === undefined) {
- // according to https://poloniex.com/fees/
- feeCost = 0; // FIXME: remove hardcoded value that may change any time
- }
+ const tag = this.safeString (transaction, 'paymentID');
+ // according to https://poloniex.com/fees/
+ const feeCost = this.safeFloat (transaction, 'fee', 0);
if (type === 'withdrawal') {
// poloniex withdrawal amount includes the fee
amount = amount - feeCost;
@@ -82183,7 +98058,7 @@ module.exports = class poloniex extends Exchange {
'currency': code,
'amount': amount,
'address': address,
- 'tag': undefined,
+ 'tag': tag,
'status': status,
'type': type,
'updated': undefined,
@@ -82197,6 +98072,28 @@ module.exports = class poloniex extends Exchange {
};
}
+ async fetchPosition (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'currencyPair': market['id'],
+ };
+ const response = await this.privatePostGetMarginPosition (this.extend (request, params));
+ //
+ // {
+ // type: "none",
+ // amount: "0.00000000",
+ // total: "0.00000000",
+ // basePrice: "0.00000000",
+ // liquidationPrice: -1,
+ // pl: "0.00000000",
+ // lendingFees: "0.00000000"
+ // }
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
nonce () {
return this.milliseconds ();
}
@@ -82234,7 +98131,2822 @@ module.exports = class poloniex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],117:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],118:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, ExchangeNotAvailable, BadResponse, BadRequest, InvalidOrder, InsufficientFunds, AuthenticationError, ArgumentsRequired, InvalidAddress, RateLimitExceeded, DDoSProtection, BadSymbol } = require ('./base/errors');
+const { TRUNCATE, TICK_SIZE } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class probit extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'probit',
+ 'name': 'ProBit',
+ 'countries': [ 'SC', 'KR' ], // Seychelles, South Korea
+ 'rateLimit': 250, // ms
+ 'has': {
+ 'CORS': true,
+ 'fetchTime': true,
+ 'fetchMarkets': true,
+ 'fetchCurrencies': true,
+ 'fetchTickers': true,
+ 'fetchTicker': true,
+ 'fetchOHLCV': true,
+ 'fetchOrderBook': true,
+ 'fetchTrades': true,
+ 'fetchBalance': true,
+ 'createOrder': true,
+ 'createMarketOrder': true,
+ 'cancelOrder': true,
+ 'fetchOrder': true,
+ 'fetchOpenOrders': true,
+ 'fetchClosedOrders': true,
+ 'fetchMyTrades': true,
+ 'fetchDepositAddress': true,
+ 'withdraw': true,
+ 'signIn': true,
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '3m': '3m',
+ '5m': '5m',
+ '10m': '10m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '4h': '4h',
+ '6h': '6h',
+ '12h': '12h',
+ '1d': '1D',
+ '1w': '1W',
+ '1M': '1M',
+ },
+ 'version': 'v1',
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/51840849/79268032-c4379480-7ea2-11ea-80b3-dd96bb29fd0d.jpg',
+ 'api': {
+ 'accounts': 'https://accounts.probit.com',
+ 'public': 'https://api.probit.com/api/exchange',
+ 'private': 'https://api.probit.com/api/exchange',
+ },
+ 'www': 'https://www.probit.com',
+ 'doc': [
+ 'https://docs-en.probit.com',
+ 'https://docs-ko.probit.com',
+ ],
+ 'fees': 'https://support.probit.com/hc/en-us/articles/360020968611-Trading-Fees',
+ 'referral': 'https://www.probit.com/r/34608773',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'market',
+ 'currency',
+ 'currency_with_platform',
+ 'time',
+ 'ticker',
+ 'order_book',
+ 'trade',
+ 'candle',
+ ],
+ },
+ 'private': {
+ 'post': [
+ 'new_order',
+ 'cancel_order',
+ 'withdrawal',
+ ],
+ 'get': [
+ 'balance',
+ 'order',
+ 'open_order',
+ 'order_history',
+ 'trade_history',
+ 'deposit_address',
+ ],
+ },
+ 'accounts': {
+ 'post': [
+ 'token',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': false,
+ 'percentage': true,
+ 'maker': 0.2 / 100,
+ 'taker': 0.2 / 100,
+ },
+ },
+ 'exceptions': {
+ 'exact': {
+ 'UNAUTHORIZED': AuthenticationError,
+ 'INVALID_ARGUMENT': BadRequest, // Parameters are not a valid format, parameters are empty, or out of range, or a parameter was sent when not required.
+ 'TRADING_UNAVAILABLE': ExchangeNotAvailable,
+ 'NOT_ENOUGH_BALANCE': InsufficientFunds,
+ 'NOT_ALLOWED_COMBINATION': BadRequest,
+ 'INVALID_ORDER': InvalidOrder, // Requested order does not exist, or it is not your order
+ 'RATE_LIMIT_EXCEEDED': RateLimitExceeded, // You are sending requests too frequently. Please try it later.
+ 'MARKET_UNAVAILABLE': ExchangeNotAvailable, // Market is closed today
+ 'INVALID_MARKET': BadSymbol, // Requested market is not exist
+ 'INVALID_CURRENCY': BadRequest, // Requested currency is not exist on ProBit system
+ 'TOO_MANY_OPEN_ORDERS': DDoSProtection, // Too many open orders
+ 'DUPLICATE_ADDRESS': InvalidAddress, // Address already exists in withdrawal address list
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ },
+ 'precisionMode': TICK_SIZE,
+ 'options': {
+ 'createMarketBuyOrderRequiresPrice': true,
+ 'timeInForce': {
+ 'limit': 'gtc',
+ 'market': 'ioc',
+ },
+ },
+ 'commonCurrencies': {
+ 'BTCBEAR': 'BEAR',
+ 'BTCBULL': 'BULL',
+ 'CBC': 'CryptoBharatCoin',
+ 'UNI': 'UNICORN Token',
+ },
+ });
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetMarket (params);
+ //
+ // {
+ // "data":[
+ // {
+ // "id":"MONA-USDT",
+ // "base_currency_id":"MONA",
+ // "quote_currency_id":"USDT",
+ // "min_price":"0.001",
+ // "max_price":"9999999999999999",
+ // "price_increment":"0.001",
+ // "min_quantity":"0.0001",
+ // "max_quantity":"9999999999999999",
+ // "quantity_precision":4,
+ // "min_cost":"1",
+ // "max_cost":"9999999999999999",
+ // "cost_precision":8,
+ // "taker_fee_rate":"0.2",
+ // "maker_fee_rate":"0.2",
+ // "show_in_ui":true,
+ // "closed":false
+ // },
+ // ]
+ // }
+ //
+ const markets = this.safeValue (response, 'data', []);
+ const result = [];
+ for (let i = 0; i < markets.length; i++) {
+ const market = markets[i];
+ const id = this.safeString (market, 'id');
+ const baseId = this.safeString (market, 'base_currency_id');
+ const quoteId = this.safeString (market, 'quote_currency_id');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const closed = this.safeValue (market, 'closed', false);
+ const active = !closed;
+ const amountPrecision = this.safeInteger (market, 'quantity_precision');
+ const costPrecision = this.safeInteger (market, 'cost_precision');
+ const precision = {
+ 'amount': 1 / Math.pow (10, amountPrecision),
+ 'price': this.safeFloat (market, 'price_increment'),
+ 'cost': 1 / Math.pow (10, costPrecision),
+ };
+ const takerFeeRate = this.safeFloat (market, 'taker_fee_rate');
+ const makerFeeRate = this.safeFloat (market, 'maker_fee_rate');
+ result.push ({
+ 'id': id,
+ 'info': market,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'active': active,
+ 'precision': precision,
+ 'taker': takerFeeRate / 100,
+ 'maker': makerFeeRate / 100,
+ 'limits': {
+ 'amount': {
+ 'min': this.safeFloat (market, 'min_quantity'),
+ 'max': this.safeFloat (market, 'max_quantity'),
+ },
+ 'price': {
+ 'min': this.safeFloat (market, 'min_price'),
+ 'max': this.safeFloat (market, 'max_price'),
+ },
+ 'cost': {
+ 'min': this.safeFloat (market, 'min_cost'),
+ 'max': this.safeFloat (market, 'max_cost'),
+ },
+ },
+ });
+ }
+ return result;
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCurrencyWithPlatform (params);
+ //
+ // {
+ // "data":[
+ // {
+ // "id":"USDT",
+ // "display_name":{"ko-kr":"테더","en-us":"Tether"},
+ // "show_in_ui":true,
+ // "platform":[
+ // {
+ // "id":"ETH",
+ // "priority":1,
+ // "deposit":true,
+ // "withdrawal":true,
+ // "currency_id":"USDT",
+ // "precision":6,
+ // "min_confirmation_count":15,
+ // "require_destination_tag":false,
+ // "display_name":{"name":{"ko-kr":"ERC-20","en-us":"ERC-20"}},
+ // "min_deposit_amount":"0",
+ // "min_withdrawal_amount":"1",
+ // "withdrawal_fee":[
+ // {"amount":"0.01","priority":2,"currency_id":"ETH"},
+ // {"amount":"1.5","priority":1,"currency_id":"USDT"},
+ // ],
+ // "deposit_fee":{},
+ // "suspended_reason":"",
+ // "deposit_suspended":false,
+ // "withdrawal_suspended":false
+ // },
+ // {
+ // "id":"OMNI",
+ // "priority":2,
+ // "deposit":true,
+ // "withdrawal":true,
+ // "currency_id":"USDT",
+ // "precision":6,
+ // "min_confirmation_count":3,
+ // "require_destination_tag":false,
+ // "display_name":{"name":{"ko-kr":"OMNI","en-us":"OMNI"}},
+ // "min_deposit_amount":"0",
+ // "min_withdrawal_amount":"5",
+ // "withdrawal_fee":[{"amount":"5","priority":1,"currency_id":"USDT"}],
+ // "deposit_fee":{},
+ // "suspended_reason":"wallet_maintenance",
+ // "deposit_suspended":false,
+ // "withdrawal_suspended":false
+ // }
+ // ],
+ // "stakeable":false,
+ // "unstakeable":false,
+ // "auto_stake":false,
+ // "auto_stake_amount":"0"
+ // }
+ // ]
+ // }
+ //
+ const currencies = this.safeValue (response, 'data');
+ const result = {};
+ for (let i = 0; i < currencies.length; i++) {
+ const currency = currencies[i];
+ const id = this.safeString (currency, 'id');
+ const code = this.safeCurrencyCode (id);
+ const displayName = this.safeValue (currency, 'display_name');
+ const name = this.safeString (displayName, 'en-us');
+ const platforms = this.safeValue (currency, 'platform', []);
+ const platformsByPriority = this.sortBy (platforms, 'priority');
+ const platform = this.safeValue (platformsByPriority, 0, {});
+ const precision = this.safeInteger (platform, 'precision');
+ const depositSuspended = this.safeValue (platform, 'deposit_suspended');
+ const withdrawalSuspended = this.safeValue (platform, 'withdrawal_suspended');
+ const active = !(depositSuspended && withdrawalSuspended);
+ const withdrawalFees = this.safeValue (platform, 'withdrawal_fee', {});
+ const withdrawalFeesByPriority = this.sortBy (withdrawalFees, 'priority');
+ const withdrawalFee = this.safeValue (withdrawalFeesByPriority, 0, {});
+ const fee = this.safeFloat (withdrawalFee, 'amount');
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': currency,
+ 'name': name,
+ 'active': active,
+ 'fee': fee,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': Math.pow (10, -precision),
+ 'max': Math.pow (10, precision),
+ },
+ 'price': {
+ 'min': Math.pow (10, -precision),
+ 'max': Math.pow (10, precision),
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'deposit': {
+ 'min': this.safeFloat (platform, 'min_deposit_amount'),
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (platform, 'min_withdrawal_amount'),
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetBalance (params);
+ //
+ // {
+ // data: [
+ // {
+ // "currency_id":"XRP",
+ // "total":"100",
+ // "available":"0",
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const result = { 'info': data };
+ for (let i = 0; i < data.length; i++) {
+ const balance = data[i];
+ const currencyId = this.safeString (balance, 'currency_id');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['total'] = this.safeFloat (balance, 'total');
+ account['free'] = this.safeFloat (balance, 'available');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market_id': market['id'],
+ };
+ const response = await this.publicGetOrderBook (this.extend (request, params));
+ //
+ // {
+ // data: [
+ // { side: 'buy', price: '0.000031', quantity: '10' },
+ // { side: 'buy', price: '0.00356007', quantity: '4.92156877' },
+ // { side: 'sell', price: '0.1857', quantity: '0.17' },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const dataBySide = this.groupBy (data, 'side');
+ return this.parseOrderBook (dataBySide, undefined, 'buy', 'sell', 'price', 'quantity');
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ if (symbols !== undefined) {
+ const marketIds = this.marketIds (symbols);
+ request['market_ids'] = marketIds.join (',');
+ }
+ const response = await this.publicGetTicker (this.extend (request, params));
+ //
+ // {
+ // "data":[
+ // {
+ // "last":"0.022902",
+ // "low":"0.021693",
+ // "high":"0.024093",
+ // "change":"-0.000047",
+ // "base_volume":"15681.986",
+ // "quote_volume":"360.514403624",
+ // "market_id":"ETH-BTC",
+ // "time":"2020-04-12T18:43:38.000Z"
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTickers (data, symbols);
+ }
+
+ parseTickers (rawTickers, symbols = undefined) {
+ const tickers = [];
+ for (let i = 0; i < rawTickers.length; i++) {
+ tickers.push (this.parseTicker (rawTickers[i]));
+ }
+ return this.filterByArray (tickers, 'symbol', symbols);
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market_ids': market['id'],
+ };
+ const response = await this.publicGetTicker (this.extend (request, params));
+ //
+ // {
+ // "data":[
+ // {
+ // "last":"0.022902",
+ // "low":"0.021693",
+ // "high":"0.024093",
+ // "change":"-0.000047",
+ // "base_volume":"15681.986",
+ // "quote_volume":"360.514403624",
+ // "market_id":"ETH-BTC",
+ // "time":"2020-04-12T18:43:38.000Z"
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const ticker = this.safeValue (data, 0);
+ if (ticker === undefined) {
+ throw new BadResponse (this.id + ' fetchTicker() returned an empty response');
+ }
+ return this.parseTicker (ticker, market);
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // {
+ // "last":"0.022902",
+ // "low":"0.021693",
+ // "high":"0.024093",
+ // "change":"-0.000047",
+ // "base_volume":"15681.986",
+ // "quote_volume":"360.514403624",
+ // "market_id":"ETH-BTC",
+ // "time":"2020-04-12T18:43:38.000Z"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (ticker, 'time'));
+ const marketId = this.safeString (ticker, 'market_id');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const close = this.safeFloat (ticker, 'last');
+ const change = this.safeFloat (ticker, 'change');
+ let percentage = undefined;
+ let open = undefined;
+ if (change !== undefined) {
+ if (close !== undefined) {
+ open = close - change;
+ percentage = (change / open) * 100;
+ }
+ }
+ const baseVolume = this.safeFloat (ticker, 'base_volume');
+ const quoteVolume = this.safeFloat (ticker, 'quote_volume');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': undefined,
+ 'bidVolume': undefined,
+ 'ask': undefined,
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': open,
+ 'close': close,
+ 'last': close,
+ 'previousClose': undefined, // previous day close
+ 'change': change,
+ 'percentage': percentage,
+ 'average': undefined,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let market = undefined;
+ const request = {
+ 'limit': 100,
+ 'start_time': this.iso8601 (0),
+ 'end_time': this.iso8601 (this.milliseconds ()),
+ };
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market_id'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['start_time'] = this.iso8601 (since);
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetTradeHistory (this.extend (request, params));
+ //
+ // {
+ // data: [
+ // {
+ // "id":"BTC-USDT:183566",
+ // "order_id":"17209376",
+ // "side":"sell",
+ // "fee_amount":"0.657396569175",
+ // "fee_currency_id":"USDT",
+ // "status":"settled",
+ // "price":"6573.96569175",
+ // "quantity":"0.1",
+ // "cost":"657.396569175",
+ // "time":"2018-08-10T06:06:46.000Z",
+ // "market_id":"BTC-USDT"
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market_id': market['id'],
+ 'limit': 100,
+ 'start_time': '1970-01-01T00:00:00.000Z',
+ 'end_time': this.iso8601 (this.milliseconds ()),
+ };
+ if (since !== undefined) {
+ request['start_time'] = this.iso8601 (since);
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.publicGetTrade (this.extend (request, params));
+ //
+ // {
+ // "data":[
+ // {
+ // "id":"ETH-BTC:3331886",
+ // "price":"0.022981",
+ // "quantity":"12.337",
+ // "time":"2020-04-12T20:55:42.371Z",
+ // "side":"sell",
+ // "tick_direction":"down"
+ // },
+ // {
+ // "id":"ETH-BTC:3331885",
+ // "price":"0.022982",
+ // "quantity":"6.472",
+ // "time":"2020-04-12T20:55:39.652Z",
+ // "side":"sell",
+ // "tick_direction":"down"
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // {
+ // "id":"ETH-BTC:3331886",
+ // "price":"0.022981",
+ // "quantity":"12.337",
+ // "time":"2020-04-12T20:55:42.371Z",
+ // "side":"sell",
+ // "tick_direction":"down"
+ // }
+ //
+ // fetchMyTrades (private)
+ //
+ // {
+ // "id":"BTC-USDT:183566",
+ // "order_id":"17209376",
+ // "side":"sell",
+ // "fee_amount":"0.657396569175",
+ // "fee_currency_id":"USDT",
+ // "status":"settled",
+ // "price":"6573.96569175",
+ // "quantity":"0.1",
+ // "cost":"657.396569175",
+ // "time":"2018-08-10T06:06:46.000Z",
+ // "market_id":"BTC-USDT"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (trade, 'time'));
+ const id = this.safeString (trade, 'id');
+ let marketId = undefined;
+ if (id !== undefined) {
+ const parts = id.split (':');
+ marketId = this.safeString (parts, 0);
+ }
+ marketId = this.safeString (trade, 'market_id', marketId);
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const side = this.safeString (trade, 'side');
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'quantity');
+ let cost = undefined;
+ if (price !== undefined) {
+ if (amount !== undefined) {
+ cost = price * amount;
+ }
+ }
+ const orderId = this.safeString (trade, 'order_id');
+ const feeCost = this.safeFloat (trade, 'fee_amount');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (trade, 'fee_currency_id');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ return {
+ 'id': id,
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'order': orderId,
+ 'type': undefined,
+ 'side': side,
+ 'takerOrMaker': undefined,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // { "data":"2020-04-12T18:54:25.390Z" }
+ //
+ const timestamp = this.parse8601 (this.safeString (response, 'data'));
+ return timestamp;
+ }
+
+ normalizeOHLCVTimestamp (timestamp, timeframe, after = false) {
+ const duration = this.parseTimeframe (timeframe);
+ if (timeframe === '1M') {
+ const iso8601 = this.iso8601 (timestamp);
+ const parts = iso8601.split ('-');
+ const year = this.safeString (parts, 0);
+ let month = this.safeInteger (parts, 1);
+ if (after) {
+ month = this.sum (month, 1);
+ }
+ if (month < 10) {
+ month = '0' + month.toString ();
+ } else {
+ month = month.toString ();
+ }
+ return year + '-' + month + '-01T00:00:00.000Z';
+ } else if (timeframe === '1w') {
+ timestamp = parseInt (timestamp / 1000);
+ const firstSunday = 259200; // 1970-01-04T00:00:00.000Z
+ const difference = timestamp - firstSunday;
+ const numWeeks = this.integerDivide (difference, duration);
+ let previousSunday = this.sum (firstSunday, numWeeks * duration);
+ if (after) {
+ previousSunday = this.sum (previousSunday, duration);
+ }
+ return this.iso8601 (previousSunday * 1000);
+ } else {
+ timestamp = parseInt (timestamp / 1000);
+ timestamp = duration * parseInt (timestamp / duration);
+ if (after) {
+ timestamp = this.sum (timestamp, duration);
+ }
+ return this.iso8601 (timestamp * 1000);
+ }
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const interval = this.timeframes[timeframe];
+ limit = (limit === undefined) ? 100 : limit;
+ let requestLimit = this.sum (limit, 1);
+ requestLimit = Math.min (1000, requestLimit); // max 1000
+ const request = {
+ 'market_ids': market['id'],
+ 'interval': interval,
+ 'sort': 'asc', // 'asc' will always include the start_time, 'desc' will always include end_time
+ 'limit': requestLimit, // max 1000
+ };
+ const now = this.milliseconds ();
+ const duration = this.parseTimeframe (timeframe);
+ let startTime = since;
+ let endTime = now;
+ if (since === undefined) {
+ if (limit === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOHLCV requires either a since argument or a limit argument');
+ } else {
+ startTime = now - limit * duration * 1000;
+ }
+ } else {
+ if (limit === undefined) {
+ endTime = now;
+ } else {
+ endTime = this.sum (since, this.sum (limit, 1) * duration * 1000);
+ }
+ }
+ const startTimeNormalized = this.normalizeOHLCVTimestamp (startTime, timeframe);
+ const endTimeNormalized = this.normalizeOHLCVTimestamp (endTime, timeframe, true);
+ request['start_time'] = startTimeNormalized;
+ request['end_time'] = endTimeNormalized;
+ const response = await this.publicGetCandle (this.extend (request, params));
+ //
+ // {
+ // "data":[
+ // {
+ // "market_id":"ETH-BTC",
+ // "open":"0.02811",
+ // "close":"0.02811",
+ // "low":"0.02811",
+ // "high":"0.02811",
+ // "base_volume":"0.0005",
+ // "quote_volume":"0.000014055",
+ // "start_time":"2018-11-30T18:19:00.000Z",
+ // "end_time":"2018-11-30T18:20:00.000Z"
+ // },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "market_id":"ETH-BTC",
+ // "open":"0.02811",
+ // "close":"0.02811",
+ // "low":"0.02811",
+ // "high":"0.02811",
+ // "base_volume":"0.0005",
+ // "quote_volume":"0.000014055",
+ // "start_time":"2018-11-30T18:19:00.000Z",
+ // "end_time":"2018-11-30T18:20:00.000Z"
+ // }
+ //
+ return [
+ this.parse8601 (this.safeString (ohlcv, 'start_time')),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'base_volume'),
+ ];
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ since = this.parse8601 (since);
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market_id'] = market['id'];
+ }
+ const response = await this.privateGetOpenOrder (this.extend (request, params));
+ const data = this.safeValue (response, 'data');
+ return this.parseOrders (data, market, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'start_time': this.iso8601 (0),
+ 'end_time': this.iso8601 (this.milliseconds ()),
+ 'limit': 100,
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market_id'] = market['id'];
+ }
+ if (since) {
+ request['start_time'] = this.iso8601 (since);
+ }
+ if (limit) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetOrderHistory (this.extend (request, params));
+ const data = this.safeValue (response, 'data');
+ return this.parseOrders (data, market, since, limit);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market_id': market['id'],
+ };
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_order_id');
+ if (clientOrderId !== undefined) {
+ request['client_order_id'] = clientOrderId;
+ } else {
+ request['order_id'] = id;
+ }
+ const query = this.omit (params, [ 'clientOrderId', 'client_order_id' ]);
+ const response = await this.privateGetOrder (this.extend (request, query));
+ const data = this.safeValue (response, 'data', []);
+ const order = this.safeValue (data, 0);
+ return this.parseOrder (order, market);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'open': 'open',
+ 'cancelled': 'canceled',
+ 'filled': 'closed',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // {
+ // id: string,
+ // user_id: string,
+ // market_id: string,
+ // type: 'orderType',
+ // side: 'side',
+ // quantity: string,
+ // limit_price: string,
+ // time_in_force: 'timeInForce',
+ // filled_cost: string,
+ // filled_quantity: string,
+ // open_quantity: string,
+ // cancelled_quantity: string,
+ // status: 'orderStatus',
+ // time: 'date',
+ // client_order_id: string,
+ // }
+ //
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const id = this.safeString (order, 'id');
+ const type = this.safeString (order, 'type');
+ const side = this.safeString (order, 'side');
+ const marketId = this.safeString (order, 'market_id');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const timestamp = this.parse8601 (this.safeString (order, 'time'));
+ let price = this.safeFloat (order, 'limit_price');
+ const filled = this.safeFloat (order, 'filled_quantity');
+ let remaining = this.safeFloat (order, 'open_quantity');
+ const canceledAmount = this.safeFloat (order, 'cancelled_quantity');
+ if (canceledAmount !== undefined) {
+ remaining = this.sum (remaining, canceledAmount);
+ }
+ const amount = this.safeFloat (order, 'quantity', this.sum (filled, remaining));
+ let cost = this.safeFloat2 (order, 'filled_cost', 'cost');
+ if (type === 'market') {
+ price = undefined;
+ }
+ let average = undefined;
+ if (filled !== undefined) {
+ if (cost === undefined) {
+ if (price !== undefined) {
+ cost = price * filled;
+ }
+ }
+ if (cost !== undefined) {
+ if (filled > 0) {
+ average = cost / filled;
+ }
+ }
+ }
+ let clientOrderId = this.safeString (order, 'client_order_id');
+ if (clientOrderId === '') {
+ clientOrderId = undefined;
+ }
+ const timeInForce = this.safeStringUpper (order, 'time_in_force');
+ return {
+ 'id': id,
+ 'info': order,
+ 'clientOrderId': clientOrderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': timeInForce,
+ 'side': side,
+ 'status': status,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'average': average,
+ 'cost': cost,
+ 'fee': undefined,
+ 'trades': undefined,
+ };
+ }
+
+ costToPrecision (symbol, cost) {
+ return this.decimalToPrecision (cost, TRUNCATE, this.markets[symbol]['precision']['cost'], this.precisionMode);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const options = this.safeValue (this.options, 'timeInForce');
+ const defaultTimeInForce = this.safeValue (options, type);
+ const timeInForce = this.safeString2 (params, 'timeInForce', 'time_in_force', defaultTimeInForce);
+ const request = {
+ 'market_id': market['id'],
+ 'type': type,
+ 'side': side,
+ 'time_in_force': timeInForce,
+ };
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_order_id');
+ if (clientOrderId !== undefined) {
+ request['client_order_id'] = clientOrderId;
+ }
+ let costToPrecision = undefined;
+ if (type === 'limit') {
+ request['limit_price'] = this.priceToPrecision (symbol, price);
+ request['quantity'] = this.amountToPrecision (symbol, amount);
+ } else if (type === 'market') {
+ // for market buy it requires the amount of quote currency to spend
+ if (side === 'buy') {
+ let cost = this.safeFloat (params, 'cost');
+ const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true);
+ if (createMarketBuyOrderRequiresPrice) {
+ if (price !== undefined) {
+ if (cost === undefined) {
+ cost = amount * price;
+ }
+ } else if (cost === undefined) {
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument for market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument or in the 'cost' extra parameter (the exchange-specific behaviour)");
+ }
+ } else {
+ cost = (cost === undefined) ? amount : cost;
+ }
+ costToPrecision = this.costToPrecision (symbol, cost);
+ request['cost'] = costToPrecision;
+ } else {
+ request['quantity'] = this.amountToPrecision (symbol, amount);
+ }
+ }
+ const query = this.omit (params, [ 'timeInForce', 'time_in_force', 'clientOrderId', 'client_order_id' ]);
+ const response = await this.privatePostNewOrder (this.extend (request, query));
+ //
+ // {
+ // data: {
+ // id: string,
+ // user_id: string,
+ // market_id: string,
+ // type: 'orderType',
+ // side: 'side',
+ // quantity: string,
+ // limit_price: string,
+ // time_in_force: 'timeInForce',
+ // filled_cost: string,
+ // filled_quantity: string,
+ // open_quantity: string,
+ // cancelled_quantity: string,
+ // status: 'orderStatus',
+ // time: 'date',
+ // client_order_id: string,
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const order = this.parseOrder (data, market);
+ // a workaround for incorrect huge amounts
+ // returned by the exchange on market buys
+ if ((type === 'market') && (side === 'buy')) {
+ order['amount'] = undefined;
+ order['cost'] = parseFloat (costToPrecision);
+ order['remaining'] = undefined;
+ }
+ return order;
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market_id': market['id'],
+ 'order_id': id,
+ };
+ const response = await this.privatePostCancelOrder (this.extend (request, params));
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data);
+ }
+
+ parseDepositAddress (depositAddress, currency = undefined) {
+ const address = this.safeString (depositAddress, 'address');
+ const tag = this.safeString (depositAddress, 'destination_tag');
+ const currencyId = this.safeString (depositAddress, 'currency_id');
+ const code = this.safeCurrencyCode (currencyId);
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': depositAddress,
+ };
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency_id': currency['id'],
+ };
+ const response = await this.privateGetDepositAddress (this.extend (request, params));
+ //
+ // {
+ // "data":[
+ // {
+ // "currency_id":"ETH",
+ // "address":"0x12e2caf3c4051ba1146e612f532901a423a9898a",
+ // "destination_tag":null
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const firstAddress = this.safeValue (data, 0);
+ if (firstAddress === undefined) {
+ throw new InvalidAddress (this.id + ' fetchDepositAddress returned an empty response');
+ }
+ return this.parseDepositAddress (firstAddress, currency);
+ }
+
+ async fetchDepositAddresses (codes = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ if (codes) {
+ const currencyIds = [];
+ for (let i = 0; i < codes.length; i++) {
+ const currency = this.currency (codes[i]);
+ currencyIds.push (currency['id']);
+ }
+ request['currency_id'] = codes.join (',');
+ }
+ const response = await this.privateGetDepositAddress (this.extend (request, params));
+ const data = this.safeValue (response, 'data', []);
+ return this.parseDepositAddresses (data);
+ }
+
+ parseDepositAddresses (addresses) {
+ const result = {};
+ for (let i = 0; i < addresses.length; i++) {
+ const address = this.parseDepositAddress (addresses[i]);
+ const code = address['currency'];
+ result[code] = address;
+ }
+ return result;
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ // In order to use this method
+ // you need to allow API withdrawal from the API Settings Page, and
+ // and register the list of withdrawal addresses and destination tags on the API Settings page
+ // you can only withdraw to the registered addresses using the API
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ if (tag === undefined) {
+ tag = '';
+ }
+ const request = {
+ 'currency_id': currency['id'],
+ // 'platform_id': 'ETH', // if omitted it will use the default platform for the currency
+ 'address': address,
+ 'destination_tag': tag,
+ 'amount': this.currencyToPrecision (code, amount),
+ // which currency to pay the withdrawal fees
+ // only applicable for currencies that accepts multiple withdrawal fee options
+ // 'fee_currency_id': 'ETH', // if omitted it will use the default fee policy for each currency
+ // whether the amount field includes fees
+ // 'include_fee': false, // makes sense only when fee_currency_id is equal to currency_id
+ };
+ const response = await this.privatePostWithdrawal (this.extend (request, params));
+ const data = this.safeValue (response, 'data');
+ return this.parseTransaction (data, currency);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ const id = this.safeString (transaction, 'id');
+ const amount = this.safeFloat (transaction, 'amount');
+ const address = this.safeString (transaction, 'address');
+ const tag = this.safeString (transaction, 'destination_tag');
+ const txid = this.safeString (transaction, 'hash');
+ const timestamp = this.parse8601 (this.safeString (transaction, 'time'));
+ const type = this.safeString (transaction, 'type');
+ const currencyId = this.safeString (transaction, 'currency_id');
+ const code = this.safeCurrencyCode (currencyId);
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const feeCost = this.safeFloat (transaction, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined && feeCost !== 0) {
+ fee = {
+ 'currency': code,
+ 'cost': feeCost,
+ };
+ }
+ return {
+ 'id': id,
+ 'currency': code,
+ 'amount': amount,
+ 'addressFrom': undefined,
+ 'address': address,
+ 'addressTo': address,
+ 'tagFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'status': status,
+ 'type': type,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': fee,
+ 'info': transaction,
+ };
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'requested': 'pending',
+ 'pending': 'pending',
+ 'confirming': 'pending',
+ 'confirmed': 'pending',
+ 'applying': 'pending',
+ 'done': 'ok',
+ 'cancelled': 'canceled',
+ 'cancelling': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ nonce () {
+ return this.milliseconds ();
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let url = this.urls['api'][api] + '/';
+ const query = this.omit (params, this.extractParams (path));
+ if (api === 'accounts') {
+ this.checkRequiredCredentials ();
+ url += this.implodeParams (path, params);
+ const auth = this.apiKey + ':' + this.secret;
+ const auth64 = this.stringToBase64 (auth);
+ headers = {
+ 'Authorization': 'Basic ' + this.decode (auth64),
+ 'Content-Type': 'application/json',
+ };
+ if (Object.keys (query).length) {
+ body = this.json (query);
+ }
+ } else {
+ url += this.version + '/';
+ if (api === 'public') {
+ url += this.implodeParams (path, params);
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (api === 'private') {
+ const now = this.milliseconds ();
+ this.checkRequiredCredentials ();
+ const expires = this.safeInteger (this.options, 'expires');
+ if ((expires === undefined) || (expires < now)) {
+ throw new AuthenticationError (this.id + ' access token expired, call signIn() method');
+ }
+ const accessToken = this.safeString (this.options, 'accessToken');
+ headers = {
+ 'Authorization': 'Bearer ' + accessToken,
+ };
+ url += this.implodeParams (path, params);
+ if (method === 'GET') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (Object.keys (query).length) {
+ body = this.json (query);
+ headers['Content-Type'] = 'application/json';
+ }
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ async signIn (params = {}) {
+ this.checkRequiredCredentials ();
+ const request = {
+ 'grant_type': 'client_credentials', // the only supported value
+ };
+ const response = await this.accountsPostToken (this.extend (request, params));
+ //
+ // {
+ // access_token: '0ttDv/2hTTn3bLi8GP1gKaneiEQ6+0hOBenPrxNQt2s=',
+ // token_type: 'bearer',
+ // expires_in: 900
+ // }
+ //
+ const expiresIn = this.safeInteger (response, 'expires_in');
+ const accessToken = this.safeString (response, 'access_token');
+ this.options['accessToken'] = accessToken;
+ this.options['expires'] = this.sum (this.milliseconds (), expiresIn * 1000);
+ return response;
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ if ('errorCode' in response) {
+ const errorCode = this.safeString (response, 'errorCode');
+ const message = this.safeString (response, 'message');
+ if (errorCode !== undefined) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ throw new ExchangeError (feedback);
+ }
+ }
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],119:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, InvalidOrder, InsufficientFunds, AuthenticationError } = require ('./base/errors');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class qtrade extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'qtrade',
+ 'name': 'qTrade',
+ 'countries': [ 'US' ],
+ 'rateLimit': 1000,
+ 'version': 'v1',
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/51840849/80491487-74a99c00-896b-11ea-821e-d307e832f13e.jpg',
+ 'api': 'https://api.qtrade.io',
+ 'www': 'https://qtrade.io',
+ 'doc': 'https://qtrade-exchange.github.io/qtrade-docs',
+ 'referral': 'https://qtrade.io/?ref=BKOQWVFGRH2C',
+ },
+ 'has': {
+ 'CORS': false,
+ 'fetchTrades': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchMarkets': true,
+ 'fetchCurrencies': true,
+ 'fetchBalance': true,
+ 'fetchOrderBook': true,
+ 'fetchOrder': true,
+ 'fetchOrders': true,
+ 'fetchMyTrades': true,
+ 'fetchClosedOrders': true,
+ 'fetchOpenOrders': true,
+ 'fetchOHLCV': true,
+ 'createOrder': true,
+ 'cancelOrder': true,
+ 'createMarketOrder': false,
+ 'withdraw': true,
+ 'fetchDepositAddress': true,
+ 'fetchTransactions': false,
+ 'fetchDeposits': true,
+ 'fetchWithdrawals': true,
+ 'fetchDeposit': true,
+ 'fetchWithdrawal': true,
+ },
+ 'timeframes': {
+ '5m': 'fivemin',
+ '15m': 'fifteenmin',
+ '30m': 'thirtymin',
+ '1h': 'onehour',
+ '2h': 'twohour',
+ '4h': 'fourhour',
+ '1d': 'oneday',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'ticker/{market_string}',
+ 'tickers',
+ 'currency/{code}',
+ 'currencies',
+ 'common',
+ 'market/{market_string}',
+ 'markets',
+ 'market/{market_string}/trades',
+ 'orderbook/{market_string}',
+ 'market/{market_string}/ohlcv/{interval}',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'me',
+ 'balances',
+ 'balances_all', // undocumented
+ 'market/{market_string}',
+ 'orders',
+ 'order/{order_id}',
+ 'trades',
+ 'withdraw/{withdraw_id}',
+ 'withdraws',
+ 'deposit/{deposit_id}',
+ 'deposits',
+ 'transfers',
+ ],
+ 'post': [
+ 'cancel_order',
+ 'withdraw',
+ 'deposit_address/{currency}',
+ 'sell_limit',
+ 'buy_limit',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.0025,
+ 'maker': 0.0,
+ },
+ 'funding': {
+ 'withdraw': {},
+ },
+ },
+ 'exceptions': {
+ 'exact': {
+ 'invalid_auth': AuthenticationError,
+ 'insuff_funds': InsufficientFunds,
+ },
+ },
+ });
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetMarkets (params);
+ //
+ // {
+ // "data":{
+ // "markets":[
+ // {
+ // "id":5,
+ // "market_currency":"BAC",
+ // "base_currency":"BTC",
+ // "maker_fee":"0.0025",
+ // "taker_fee":"0.0025",
+ // "metadata":{
+ // "delisting_date":"7/15/2018",
+ // "market_notices":[
+ // {
+ // "message":"Delisting Notice: This market has been delisted due to low volume. Please cancel your orders and withdraw your funds by 7/15/2018.",
+ // "type":"warning"
+ // }
+ // ]
+ // },
+ // "can_trade":false,
+ // "can_cancel":true,
+ // "can_view":false,
+ // "market_string":"BAC_BTC",
+ // "minimum_sell_amount":"0.0001",
+ // "minimum_buy_value":"0.0001",
+ // "market_precision":8,
+ // "base_precision":8
+ // },
+ // ],
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const markets = this.safeValue (data, 'markets', []);
+ const result = [];
+ for (let i = 0; i < markets.length; i++) {
+ const market = markets[i];
+ const marketId = this.safeString (market, 'market_string');
+ const numericId = this.safeInteger (market, 'id');
+ const baseId = this.safeString (market, 'market_currency');
+ const quoteId = this.safeString (market, 'base_currency');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const precision = {
+ 'amount': this.safeInteger (market, 'market_precision'),
+ 'price': this.safeInteger (market, 'base_precision'),
+ };
+ const canView = this.safeValue (market, 'can_view', false);
+ const canTrade = this.safeValue (market, 'can_trade', false);
+ const active = canTrade && canView;
+ result.push ({
+ 'symbol': symbol,
+ 'id': marketId,
+ 'numericId': numericId,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'base': base,
+ 'quote': quote,
+ 'active': active,
+ 'precision': precision,
+ 'taker': this.safeFloat (market, 'taker_fee'),
+ 'maker': this.safeFloat (market, 'maker_fee'),
+ 'limits': {
+ 'amount': {
+ 'min': this.safeFloat (market, 'minimum_buy_value'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ 'info': market,
+ });
+ }
+ return result;
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCurrencies (params);
+ //
+ // {
+ // "data":{
+ // "currencies":[
+ // {
+ // "code":"DGB",
+ // "long_name":"Digibyte",
+ // "type":"bitcoin_like",
+ // "precision":8,
+ // "config":{
+ // "price":0.0035,
+ // "withdraw_fee":"10",
+ // "deposit_types":[
+ // {
+ // "label":"Address",
+ // "lookup_mode":"address",
+ // "render_type":"address",
+ // "deposit_type":"address",
+ // "lookup_config":{}
+ // }
+ // ],
+ // "default_signer":103,
+ // "address_version":30,
+ // "satoshi_per_byte":300,
+ // "required_confirmations":200,
+ // "required_generate_confirmations":300
+ // },
+ // "metadata":{},
+ // "minimum_order":"0.0001",
+ // "status":"ok",
+ // "can_withdraw":true,
+ // "delisted":false,
+ // "deposit_disabled":false,
+ // "withdraw_disabled":false,
+ // "deposit_warn_codes":[],
+ // "withdraw_warn_codes":[]
+ // },
+ // ],
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const currencies = this.safeValue (data, 'currencies', []);
+ const result = {};
+ for (let i = 0; i < currencies.length; i++) {
+ const currency = currencies[i];
+ const id = this.safeString (currency, 'code');
+ const code = this.safeCurrencyCode (id);
+ const name = this.safeString (currency, 'long_name');
+ const type = this.safeString (currency, 'type');
+ const canWithdraw = this.safeValue (currency, 'can_withdraw', true);
+ const depositDisabled = this.safeValue (currency, 'deposit_disabled', false);
+ const config = this.safeValue (currency, 'config', {});
+ const status = this.safeString (currency, 'status');
+ const active = canWithdraw && (status === 'ok') && !depositDisabled;
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': currency,
+ 'type': type,
+ 'name': name,
+ 'fee': this.safeFloat (config, 'withdraw_fee'),
+ 'precision': this.safeInteger (currency, 'precision'),
+ 'active': active,
+ 'limits': {
+ 'amount': {
+ 'min': this.safeFloat (currency, 'minimum_order'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ return result;
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "time":"2019-12-07T22:55:00Z",
+ // "open":"0.00197",
+ // "high":"0.00197",
+ // "low":"0.00197",
+ // "close":"0.00197",
+ // "volume":"0.00016676",
+ // "market_volume":"0.08465047"
+ // }
+ //
+ return [
+ this.parse8601 (this.safeString (ohlcv, 'time')),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'market_volume'),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '5m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market_string': market['id'],
+ 'interval': this.timeframes[timeframe],
+ };
+ const response = await this.publicGetMarketMarketStringOhlcvInterval (this.extend (request, params));
+ //
+ // {
+ // "data":{
+ // "slices":[
+ // {"time":"2019-12-07T22:55:00Z","open":"0.00197","high":"0.00197","low":"0.00197","close":"0.00197","volume":"0.00016676","market_volume":"0.08465047"},
+ // {"time":"2019-12-07T23:00:00Z","open":"0.00197","high":"0.00197","low":"0.00197","close":"0.00197","volume":"0","market_volume":"0"},
+ // {"time":"2019-12-07T23:05:00Z","open":"0.00197","high":"0.00197","low":"0.00197","close":"0.00197","volume":"0","market_volume":"0"},
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const ohlcvs = this.safeValue (data, 'slices', []);
+ return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const marketId = this.marketId (symbol);
+ const request = { 'market_string': marketId };
+ const response = await this.publicGetOrderbookMarketString (this.extend (request, params));
+ //
+ // {
+ // "data":{
+ // "buy":{
+ // "0.00700015":"4.76196367",
+ // "0.00700017":"1.89755391",
+ // "0.00700018":"2.13214088",
+ // },
+ // "last_change":1588539869958811,
+ // "sell":{
+ // "0.02418662":"0.19513696",
+ // "0.02465627":"0.2439212",
+ // "0.02530277":"0.663475931274359255",
+ // }
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const orderbook = {};
+ const sides = { 'buy': 'bids', 'sell': 'asks' };
+ const keys = Object.keys (sides);
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i];
+ const side = sides[key];
+ const bidasks = this.safeValue (data, key, {});
+ const prices = Object.keys (bidasks);
+ const result = [];
+ for (let j = 0; j < prices.length; j++) {
+ const priceAsString = prices[j];
+ const price = this.safeFloat (prices, j);
+ const amount = this.safeFloat (bidasks, priceAsString);
+ result.push ([ price, amount ]);
+ }
+ orderbook[side] = result;
+ }
+ const timestamp = this.safeIntegerProduct (data, 'last_change', 0.001);
+ return this.parseOrderBook (orderbook, timestamp);
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker, fetchTickers
+ //
+ // {
+ // "ask":"0.02423119",
+ // "bid":"0.0230939",
+ // "day_avg_price":"0.0247031874349301",
+ // "day_change":"-0.0237543162270376",
+ // "day_high":"0.02470552",
+ // "day_low":"0.02470172",
+ // "day_open":"0.02530277",
+ // "day_volume_base":"0.00268074",
+ // "day_volume_market":"0.10851798",
+ // "id":41,
+ // "id_hr":"ETH_BTC",
+ // "last":"0.02470172",
+ // "last_change":1588533365354609
+ // }
+ //
+ const marketId = this.safeString (ticker, 'id_hr');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const timestamp = this.safeIntegerProduct (ticker, 'last_change', 0.001);
+ const previous = this.safeFloat (ticker, 'day_open');
+ const last = this.safeFloat (ticker, 'last');
+ const day_change = this.safeFloat (ticker, 'day_change');
+ let percentage = undefined;
+ let change = undefined;
+ let average = this.safeFloat (ticker, 'day_avg_price');
+ if (day_change !== undefined) {
+ percentage = day_change * 100;
+ if (previous !== undefined) {
+ change = day_change * previous;
+ }
+ }
+ if ((average === undefined) && (last !== undefined) && (previous !== undefined)) {
+ average = this.sum (last, previous) / 2;
+ }
+ const baseVolume = this.safeFloat (ticker, 'day_volume_market');
+ const quoteVolume = this.safeFloat (ticker, 'day_volume_base');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'day_high'),
+ 'low': this.safeFloat (ticker, 'day_low'),
+ 'bid': this.safeFloat (ticker, 'bid'),
+ 'bidVolume': undefined,
+ 'ask': this.safeFloat (ticker, 'ask'),
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': previous,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetTickers (params);
+ //
+ // {
+ // "data":{
+ // "markets":[
+ // {
+ // "ask":"0.0000003",
+ // "bid":"0.00000029",
+ // "day_avg_price":"0.0000002999979728",
+ // "day_change":"0.0344827586206897",
+ // "day_high":"0.0000003",
+ // "day_low":"0.0000003",
+ // "day_open":"0.00000029",
+ // "day_volume_base":"0.00591958",
+ // "day_volume_market":"19732.06666665",
+ // "id":36,
+ // "id_hr":"DOGE_BTC",
+ // "last":"0.0000003",
+ // "last_change":1588534202130778
+ // },
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const tickers = this.safeValue (data, 'markets', []);
+ const result = {};
+ for (let i = 0; i < tickers.length; i++) {
+ const ticker = this.parseTicker (tickers[i]);
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market_string': market['id'],
+ };
+ const response = await this.publicGetTickerMarketString (this.extend (request, params));
+ //
+ // {
+ // "data":{
+ // "ask":"0.02423119",
+ // "bid":"0.0230939",
+ // "day_avg_price":"0.0247031874349301",
+ // "day_change":"-0.0237543162270376",
+ // "day_high":"0.02470552",
+ // "day_low":"0.02470172",
+ // "day_open":"0.02530277",
+ // "day_volume_base":"0.00268074",
+ // "day_volume_market":"0.10851798",
+ // "id":41,
+ // "id_hr":"ETH_BTC",
+ // "last":"0.02470172",
+ // "last_change":1588533365354609
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTicker (data, market);
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market_string': market['id'],
+ // 'older_than': 123, // returns trades with id < older_than
+ // 'newer_than': 123, // returns trades with id > newer_than
+ };
+ const response = await this.publicGetMarketMarketStringTrades (this.extend (request, params));
+ //
+ // {
+ // "data":{
+ // "trades":[
+ // {
+ // "id":85507,
+ // "amount":"0.09390502",
+ // "price":"0.02556325",
+ // "base_volume":"0.00240051",
+ // "seller_taker":true,
+ // "side":"sell",
+ // "created_at":"0001-01-01T00:00:00Z",
+ // "created_at_ts":1581560391338718
+ // },
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'trades', []);
+ return this.parseTrades (trades, market, since, limit);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'desc': true, // Returns newest trades first when true
+ // 'older_than': 123, // returns trades with id < older_than
+ // 'newer_than': 123, // returns trades with id > newer_than
+ };
+ let market = undefined;
+ const numericId = this.safeValue (params, 'market_id');
+ if (numericId !== undefined) {
+ request['market_id'] = numericId; // mutually exclusive with market_string
+ } else if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market_string'] = market['id'];
+ }
+ const response = await this.privateGetTrades (this.extend (request, params));
+ //
+ // {
+ // "data":{
+ // "trades":[
+ // {
+ // "id":107331,
+ // "market_amount":"0.1082536946986",
+ // "price":"0.0230939",
+ // "base_amount":"0.00249999",
+ // "order_id":13790596,
+ // "market_id":41,
+ // "market_string":"ETH_BTC",
+ // "taker":true,
+ // "base_fee":"0.00001249",
+ // "side":"sell",
+ // "created_at":"2020-05-04T06:08:18.513413Z"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'trades', []);
+ return this.parseTrades (trades, market, since, limit);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // {
+ // "id":85507,
+ // "amount":"0.09390502",
+ // "price":"0.02556325",
+ // "base_volume":"0.00240051",
+ // "seller_taker":true,
+ // "side":"sell",
+ // "created_at":"0001-01-01T00:00:00Z",
+ // "created_at_ts":1581560391338718
+ // }
+ //
+ // fetchMyTrades (private)
+ //
+ // {
+ // "id":107331,
+ // "market_amount":"0.1082536946986",
+ // "price":"0.0230939",
+ // "base_amount":"0.00249999",
+ // "order_id":13790596,
+ // "market_id":41,
+ // "market_string":"ETH_BTC",
+ // "taker":true,
+ // "base_fee":"0.00001249",
+ // "side":"sell",
+ // "created_at":"2020-05-04T06:08:18.513413Z"
+ // }
+ //
+ // createOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders
+ //
+ // {
+ // "base_amount": "9.58970687",
+ // "base_fee": "0.02397426",
+ // "created_at": "0001-01-01T00:00:00Z",
+ // "id": 0,
+ // "market_amount": "0.97179355",
+ // "price": "9.86804952",
+ // "taker": true
+ // }
+ //
+ const id = this.safeString (trade, 'id');
+ let timestamp = this.safeIntegerProduct (trade, 'created_at_ts', 0.001);
+ if (timestamp === undefined) {
+ timestamp = this.parse8601 (this.safeString (trade, 'created_at'));
+ }
+ const side = this.safeString (trade, 'side');
+ const marketId = this.safeString (trade, 'market_string');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ let cost = this.safeFloat2 (trade, 'base_volume', 'base_amount');
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat2 (trade, 'market_amount', 'amount');
+ if ((cost === undefined) && (amount !== undefined) && (price !== undefined)) {
+ if (price !== undefined) {
+ cost = price * amount;
+ }
+ }
+ let fee = undefined;
+ const feeCost = this.safeFloat (trade, 'base_fee');
+ if (feeCost !== undefined) {
+ const feeCurrencyCode = (market === undefined) ? undefined : market['quote'];
+ fee = {
+ 'currency': feeCurrencyCode,
+ 'cost': feeCost,
+ };
+ }
+ const taker = this.safeValue (trade, 'taker', true);
+ const takerOrMaker = taker ? 'taker' : 'maker';
+ const orderId = this.safeString (trade, 'order_id');
+ const result = {
+ 'id': id,
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'order': orderId,
+ 'type': undefined,
+ 'side': side,
+ 'takerOrMaker': takerOrMaker,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ return result;
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetBalancesAll (params);
+ //
+ // {
+ // "data":{
+ // "balances": [
+ // { "balance": "100000000", "currency": "BCH" },
+ // { "balance": "99992435.78253015", "currency": "LTC" },
+ // { "balance": "99927153.76074182", "currency": "BTC" },
+ // ],
+ // "order_balances":[],
+ // "limit_used":0,
+ // "limit_remaining":4000,
+ // "limit":4000
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ let balances = this.safeValue (data, 'balances', []);
+ const result = {
+ 'info': response,
+ };
+ for (let i = 0; i < balances.length; i++) {
+ const balance = balances[i];
+ const currencyId = this.safeString (balance, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = (code in result) ? result[code] : this.account ();
+ account['free'] = this.safeFloat (balance, 'balance');
+ account['used'] = 0;
+ result[code] = account;
+ }
+ balances = this.safeValue (data, 'order_balances', []);
+ for (let i = 0; i < balances.length; i++) {
+ const balance = balances[i];
+ const currencyId = this.safeString (balance, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = (code in result) ? result[code] : this.account ();
+ account['used'] = this.safeFloat (balance, 'balance');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ if (type !== 'limit') {
+ throw new InvalidOrder (this.id + ' createOrder() allows limit orders only');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'amount': this.amountToPrecision (symbol, amount),
+ 'market_id': market['numericId'],
+ 'price': this.priceToPrecision (symbol, price),
+ };
+ const method = (side === 'sell') ? 'privatePostSellLimit' : 'privatePostBuyLimit';
+ const response = await this[method] (this.extend (request, params));
+ //
+ // {
+ // "data": {
+ // "order": {
+ // "created_at": "2018-04-06T20:46:52.899248Z",
+ // "id": 13253,
+ // "market_amount": "1",
+ // "market_amount_remaining": "0",
+ // "market_id": 1,
+ // "open": false,
+ // "order_type": "sell_limit",
+ // "price": "0.01",
+ // "trades": [
+ // {
+ // "base_amount": "0.27834267",
+ // "base_fee": "0.00069585",
+ // "created_at": "0001-01-01T00:00:00Z",
+ // "id": 0,
+ // "market_amount": "0.02820645",
+ // "price": "9.86805058",
+ // "taker": true
+ // },
+ // {
+ // "base_amount": "9.58970687",
+ // "base_fee": "0.02397426",
+ // "created_at": "0001-01-01T00:00:00Z",
+ // "id": 0,
+ // "market_amount": "0.97179355",
+ // "price": "9.86804952",
+ // "taker": true
+ // }
+ // ]
+ // }
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const order = this.safeValue (data, 'order', {});
+ return this.parseOrder (order, market);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // "created_at": "2018-04-06T20:46:52.899248Z",
+ // "id": 13253,
+ // "market_amount": "1",
+ // "market_amount_remaining": "0",
+ // "market_id": 1,
+ // "open": false,
+ // "order_type": "sell_limit",
+ // "price": "0.01",
+ // "trades": [
+ // {
+ // "base_amount": "0.27834267",
+ // "base_fee": "0.00069585",
+ // "created_at": "0001-01-01T00:00:00Z",
+ // "id": 0,
+ // "market_amount": "0.02820645",
+ // "price": "9.86805058",
+ // "taker": true
+ // },
+ // {
+ // "base_amount": "9.58970687",
+ // "base_fee": "0.02397426",
+ // "created_at": "0001-01-01T00:00:00Z",
+ // "id": 0,
+ // "market_amount": "0.97179355",
+ // "price": "9.86804952",
+ // "taker": true
+ // }
+ // ]
+ // }
+ //
+ // fetchOrder
+ //
+ // {
+ // id: 13790596,
+ // market_amount: "0.15",
+ // market_amount_remaining: "0",
+ // created_at: "2020-05-04T06:08:18.513413Z",
+ // price: "0.0230939",
+ // base_amount: "0",
+ // order_type: "sell_limit",
+ // market_id: 41,
+ // market_string: "ETH_BTC",
+ // open: false,
+ // trades: [
+ // {
+ // id: 107331,
+ // market_amount: "0.1082536946986",
+ // price: "0.0230939",
+ // base_amount: "0.00249999",
+ // taker: true,
+ // base_fee: "0.00001249",
+ // created_at: "2020-05-04T06:08:18.513413Z",
+ // }
+ // ],
+ // close_reason: "canceled"
+ // }
+ //
+ const id = this.safeString (order, 'id');
+ const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
+ const sideType = this.safeString (order, 'order_type');
+ let orderType = undefined;
+ let side = undefined;
+ if (sideType !== undefined) {
+ const parts = sideType.split ('_');
+ side = this.safeString (parts, 0);
+ orderType = this.safeString (parts, 1);
+ }
+ const price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'market_amount');
+ let remaining = this.safeFloat (order, 'market_amount_remaining');
+ let filled = undefined;
+ const open = this.safeValue (order, 'open', false);
+ const closeReason = this.safeString (order, 'close_reason');
+ let status = undefined;
+ if (open) {
+ status = 'open';
+ } else if (closeReason === 'canceled') {
+ status = 'canceled';
+ } else {
+ status = 'closed';
+ }
+ const marketId = this.safeString (order, 'market_string');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const rawTrades = this.safeValue (order, 'trades', []);
+ const parsedTrades = this.parseTrades (rawTrades, market, undefined, undefined, {
+ 'order': id,
+ 'side': side,
+ 'type': orderType,
+ });
+ const numTrades = parsedTrades.length;
+ let lastTradeTimestamp = undefined;
+ let feeCost = undefined;
+ let cost = undefined;
+ if (numTrades > 0) {
+ feeCost = 0;
+ cost = 0;
+ filled = 0;
+ remaining = amount;
+ for (let i = 0; i < parsedTrades.length; i++) {
+ const trade = parsedTrades[i];
+ feeCost = this.sum (trade['fee']['cost'], feeCost);
+ lastTradeTimestamp = this.safeInteger (trade, 'timestamp');
+ cost = this.sum (trade['cost'], cost);
+ filled = this.sum (trade['amount'], filled);
+ remaining = Math.max (0, remaining - trade['amount']);
+ }
+ }
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyCode = (market === undefined) ? undefined : market['quote'];
+ fee = {
+ 'currency': feeCurrencyCode,
+ 'cost': feeCost,
+ };
+ }
+ if ((amount !== undefined) && (remaining !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ let average = undefined;
+ if (filled !== undefined) {
+ if ((price !== undefined) && (cost === undefined)) {
+ cost = filled * price;
+ }
+ if ((cost !== undefined) && (filled > 0)) {
+ average = cost / filled;
+ }
+ }
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'symbol': symbol,
+ 'type': orderType,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'average': average,
+ 'amount': amount,
+ 'remaining': remaining,
+ 'filled': filled,
+ 'status': status,
+ 'fee': fee,
+ 'cost': cost,
+ 'trades': parsedTrades,
+ };
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ const request = {
+ 'id': parseInt (id),
+ };
+ // successful cancellation returns 200 with no payload
+ return await this.privatePostCancelOrder (this.extend (request, params));
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = { 'order_id': id };
+ const response = await this.privateGetOrderOrderId (this.extend (request, params));
+ //
+ // {
+ // "data":{
+ // "order":{
+ // "id":13790596,
+ // "market_amount":"0.15",
+ // "market_amount_remaining":"0.0417463053014",
+ // "created_at":"2020-05-04T06:08:18.513413Z",
+ // "price":"0.0230939",
+ // "order_type":"sell_limit",
+ // "market_id":41,
+ // "market_string":"ETH_BTC",
+ // "open":true,
+ // "trades":[
+ // {
+ // "id":107331,
+ // "market_amount":"0.1082536946986",
+ // "price":"0.0230939",
+ // "base_amount":"0.00249999",
+ // "taker":true,
+ // "base_fee":"0.00001249",
+ // "created_at":"2020-05-04T06:08:18.513413Z"
+ // }
+ // ]
+ // }
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const order = this.safeValue (data, 'order', {});
+ return this.parseOrder (order);
+ }
+
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'open': true,
+ // 'older_than': 123, // returns orders with id < older_than
+ // 'newer_than': 123, // returns orders with id > newer_than
+ };
+ let market = undefined;
+ const numericId = this.safeValue (params, 'market_id');
+ if (numericId !== undefined) {
+ request['market_id'] = numericId; // mutually exclusive with market_string
+ } else if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market_string'] = market['id'];
+ }
+ const response = await this.privateGetOrders (this.extend (request, params));
+ //
+ // {
+ // "data":{
+ // "orders":[
+ // {
+ // "id":13790596,
+ // "market_amount":"0.15",
+ // "market_amount_remaining":"0.0417463053014",
+ // "created_at":"2020-05-04T06:08:18.513413Z",
+ // "price":"0.0230939",
+ // "order_type":"sell_limit",
+ // "market_id":41,
+ // "market_string":"ETH_BTC",
+ // "open":true,
+ // "trades":[
+ // {
+ // "id":107331,
+ // "market_amount":"0.1082536946986",
+ // "price":"0.0230939",
+ // "base_amount":"0.00249999",
+ // "taker":true,
+ // "base_fee":"0.00001249",
+ // "created_at":"2020-05-04T06:08:18.513413Z"
+ // }
+ // ]
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const orders = this.safeValue (data, 'orders', []);
+ return this.parseOrders (orders, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = { 'open': true };
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = { 'open': false };
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ parseDepositAddress (depositAddress, currency = undefined) {
+ //
+ // {
+ // "address":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "currency_status":"ok",
+ // "deposit_methods":{
+ // "address":{
+ // "deposit_type":"address",
+ // "render_type":"address",
+ // "label":"Address",
+ // "address":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // },
+ // },
+ // }
+ //
+ const code = (currency === undefined) ? undefined : currency['code'];
+ let address = this.safeString (depositAddress, 'address');
+ let tag = undefined;
+ if (address !== undefined) {
+ const parts = address.split (':');
+ address = this.safeString (parts, 0);
+ tag = this.safeString (parts, 1);
+ }
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': depositAddress,
+ };
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privatePostDepositAddressCurrency (this.extend (request, params));
+ //
+ // {
+ // "data":{
+ // "address":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "currency_status":"ok",
+ // "deposit_methods":{
+ // "address":{
+ // "deposit_type":"address",
+ // "render_type":"address",
+ // "label":"Address",
+ // "address":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // },
+ // },
+ // },
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseDepositAddress (data, currency);
+ }
+
+ async fetchDeposit (id, code = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'deposit_id': id,
+ };
+ const response = await this.privateGetDepositDepositId (this.extend (request, params));
+ //
+ // {
+ // "data":{
+ // "deposit":{
+ // "id":"0xaa6e65ed274c4786e5dec3671de96f81021cacdbc453b1a133ab84356f3620a0",
+ // "amount":"0.13",
+ // "currency":"ETH",
+ // "address":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "status":"credited",
+ // "relay_status":"",
+ // "network_data":{
+ // "confirms":87,
+ // "sweep_txid":"0xa16e65ed274d4686e5dec3671de96f81021cacdbc453b1a133ab85356f3630a0",
+ // "sweep_balance":"0.150000000000000000",
+ // "confirms_required":80,
+ // "unsigned_sweep_tx":{
+ // "chainId":1,
+ // "from":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "gas":"0x5208",
+ // "gasPrice":"0x19b45a500",
+ // "nonce":"0x0",
+ // "to":"0x76Cd80202a2C31e9D8F595a31ed071CE7F75BB93",
+ // "value":"0x214646b6347d800"
+ // },
+ // "txid":"0xaa6e65ed274c4786e5dec3671de96f81021cacdbc453b1a133ab84356f3620a0",
+ // "tx_index":"0x6f",
+ // "tx_value":"0.130000000000000000",
+ // "key_index":311,
+ // "blockheight":9877869,
+ // "signed_sweep_tx":{
+ // "hash":"0xa16e65ed274d4686e5dec3671de96f81021cacdbc453b1a133ab85356f3630a0",
+ // "rawTransaction":"0xd86c8085019b45a1008252099476cb80202b2c31e9d7f595a31fd071ce7f75bb93880214646b6347d8008046a08c6e3bfe8b25bff2b6851c87ea17c63d7b23591210ab0779a568eaa43dc40435a030e964bb2b667072ea7cbc8ab554403e3f3ead9b554743f2fdc2b1e06e998df9"
+ // },
+ // "estimated_sweep_tx_fee":144900000000000
+ // },
+ // "created_at":"2020-05-04T05:38:42.145162Z"
+ // }
+ // }
+ // }
+ const data = this.safeValue (response, 'data', {});
+ const deposit = this.safeValue (data, 'deposit', {});
+ return this.parseTransaction (deposit);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ const response = await this.privateGetDeposits (params);
+ //
+ // {
+ // "data":{
+ // "deposits":[
+ // {
+ // "id":"0xaa6e65ed274c4786e5dec3671de96f81021cacdbc453b1a133ab84356f3620a0",
+ // "amount":"0.13",
+ // "currency":"ETH",
+ // "address":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "status":"credited",
+ // "relay_status":"",
+ // "network_data":{
+ // "confirms":87,
+ // "sweep_txid":"0xa16e65ed274d4686e5dec3671de96f81021cacdbc453b1a133ab85356f3630a0",
+ // "sweep_balance":"0.150000000000000000",
+ // "confirms_required":80,
+ // "unsigned_sweep_tx":{
+ // "chainId":1,
+ // "from":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "gas":"0x5208",
+ // "gasPrice":"0x19b45a500",
+ // "nonce":"0x0",
+ // "to":"0x76Cd80202a2C31e9D8F595a31ed071CE7F75BB93",
+ // "value":"0x214646b6347d800"
+ // },
+ // "txid":"0xaa6e65ed274c4786e5dec3671de96f81021cacdbc453b1a133ab84356f3620a0",
+ // "tx_index":"0x6f",
+ // "tx_value":"0.130000000000000000",
+ // "key_index":311,
+ // "blockheight":9877869,
+ // "signed_sweep_tx":{
+ // "hash":"0xa16e65ed274d4686e5dec3671de96f81021cacdbc453b1a133ab85356f3630a0",
+ // "rawTransaction":"0xd86c8085019b45a1008252099476cb80202b2c31e9d7f595a31fd071ce7f75bb93880214646b6347d8008046a08c6e3bfe8b25bff2b6851c87ea17c63d7b23591210ab0779a568eaa43dc40435a030e964bb2b667072ea7cbc8ab554403e3f3ead9b554743f2fdc2b1e06e998df9"
+ // },
+ // "estimated_sweep_tx_fee":144900000000000
+ // },
+ // "created_at":"2020-05-04T05:38:42.145162Z"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const deposits = this.safeValue (data, 'deposits', []);
+ return this.parseTransactions (deposits, currency, since, limit);
+ }
+
+ async fetchWithdrawal (id, code = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'withdraw_id': id,
+ };
+ const response = await this.privateGetWithdrawWithdrawId (this.extend (request, params));
+ //
+ // {
+ // data: {
+ // withdraw: {
+ // "id":25524,
+ // "amount":"0.0417463053014",
+ // "user_id":0,
+ // "currency":"ETH",
+ // "network_data":{
+ // "unsigned_tx":{
+ // "chainId":1,
+ // "from":"0x76Cd80202a2C31e9D8F595a31ed071CE7F75BB93",
+ // "gas":"0x5208",
+ // "gasPrice":"0x20c8558e9",
+ // "nonce":"0xf3",
+ // "to":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "value":"0x71712bcd113308"
+ // },
+ // "estimated_tx_fee":184800004893000,
+ // "confirms_required":80,
+ // "txid":"0x79439b62473d61d99ce1dc6c3b8a417da36d45323a394bb0d4af870608fef38d",
+ // "confirms":83,
+ // "signed_tx":{
+ // "hash":"0x79439b62473d61d99ce1dc6c3b8a417da36d45323a394bb0d4af870608fef38d",
+ // "rawTransaction":"0xf86c81f385021c8558e98252089401b0a9b7b4cde774af0f3e87cb4f1c2ccdba08068771712acd1133078025a0088157d119d924d47413c81b91b9f18ff148623a2ef13dab1895ca3ba546b771a046a021b1e1f64d1a60bb66c19231f641b352326188a9ed3b931b698a939f78d0"
+ // }
+ // },
+ // "address":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "status":"confirmed",
+ // "relay_status":"",
+ // "created_at":"2020-05-05T06:32:19.907061Z",
+ // "cancel_requested":false
+ // }
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const withdrawal = this.safeValue (data, 'withdraw', {});
+ return this.parseTransaction (withdrawal);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ const response = await this.privateGetWithdraws (params);
+ // {
+ // "data":{
+ // "withdraws":[
+ // {
+ // "id":25524,
+ // "amount":"0.0417463053014",
+ // "user_id":0,
+ // "currency":"ETH",
+ // "network_data":{
+ // "unsigned_tx":{
+ // "chainId":1,
+ // "from":"0x76Cd80202a2C31e9D8F595a31ed071CE7F75BB93",
+ // "gas":"0x5208",
+ // "gasPrice":"0x20c8558e9",
+ // "nonce":"0xf3",
+ // "to":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "value":"0x71712bcd113308"
+ // },
+ // "estimated_tx_fee":184800004893000,
+ // "confirms_required":80,
+ // "txid":"0x79439b62473d61d99ce1dc6c3b8a417da36d45323a394bb0d4af870608fef38d",
+ // "confirms":83,
+ // "signed_tx":{
+ // "hash":"0x79439b62473d61d99ce1dc6c3b8a417da36d45323a394bb0d4af870608fef38d",
+ // "rawTransaction":"0xf86c81f385021c8558e98252089401b0a9b7b4cde774af0f3e87cb4f1c2ccdba08068771712acd1133078025a0088157d119d924d47413c81b91b9f18ff148623a2ef13dab1895ca3ba546b771a046a021b1e1f64d1a60bb66c19231f641b352326188a9ed3b931b698a939f78d0"
+ // }
+ // },
+ // "address":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "status":"confirmed",
+ // "relay_status":"",
+ // "created_at":"2020-05-05T06:32:19.907061Z",
+ // "cancel_requested":false
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const withdrawals = this.safeValue (data, 'withdraws', []);
+ return this.parseTransactions (withdrawals, currency, since, limit);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // fetchDeposits, fetchDeposit
+ //
+ // {
+ // "id":"0xaa6e65ed274c4786e5dec3671de96f81021cacdbc453b1a133ab84356f3620a0",
+ // "amount":"0.13",
+ // "currency":"ETH",
+ // "address":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "status":"credited",
+ // "relay_status":"",
+ // "network_data":{
+ // "confirms":87,
+ // "sweep_txid":"0xa16e65ed274d4686e5dec3671de96f81021cacdbc453b1a133ab85356f3630a0",
+ // "sweep_balance":"0.150000000000000000",
+ // "confirms_required":80,
+ // "unsigned_sweep_tx":{
+ // "chainId":1,
+ // "from":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "gas":"0x5208",
+ // "gasPrice":"0x19b45a500",
+ // "nonce":"0x0",
+ // "to":"0x76Cd80202a2C31e9D8F595a31ed071CE7F75BB93",
+ // "value":"0x214646b6347d800"
+ // },
+ // "txid":"0xaa6e65ed274c4786e5dec3671de96f81021cacdbc453b1a133ab84356f3620a0",
+ // "tx_index":"0x6f",
+ // "tx_value":"0.130000000000000000",
+ // "key_index":311,
+ // "blockheight":9877869,
+ // "signed_sweep_tx":{
+ // "hash":"0xa16e65ed274d4686e5dec3671de96f81021cacdbc453b1a133ab85356f3630a0",
+ // "rawTransaction":"0xd86c8085019b45a1008252099476cb80202b2c31e9d7f595a31fd071ce7f75bb93880214646b6347d8008046a08c6e3bfe8b25bff2b6851c87ea17c63d7b23591210ab0779a568eaa43dc40435a030e964bb2b667072ea7cbc8ab554403e3f3ead9b554743f2fdc2b1e06e998df9"
+ // },
+ // "estimated_sweep_tx_fee":144900000000000
+ // },
+ // "created_at":"2020-05-04T05:38:42.145162Z"
+ // }
+ //
+ // fetchWithdrawals, fetchWithdrawal
+ //
+ // {
+ // "id":25524,
+ // "amount":"0.0417463053014",
+ // "user_id":0,
+ // "currency":"ETH",
+ // "network_data":{
+ // "unsigned_tx":{
+ // "chainId":1,
+ // "from":"0x76Cd80202a2C31e9D8F595a31ed071CE7F75BB93",
+ // "gas":"0x5208",
+ // "gasPrice":"0x20c8558e9",
+ // "nonce":"0xf3",
+ // "to":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "value":"0x71712bcd113308"
+ // },
+ // "estimated_tx_fee":184800004893000,
+ // "confirms_required":80,
+ // "txid":"0x79439b62473d61d99ce1dc6c3b8a417da36d45323a394bb0d4af870608fef38d",
+ // "confirms":83,
+ // "signed_tx":{
+ // "hash":"0x79439b62473d61d99ce1dc6c3b8a417da36d45323a394bb0d4af870608fef38d",
+ // "rawTransaction":"0xf86c81f385021c8558e98252089401b0a9b7b4cde774af0f3e87cb4f1c2ccdba08068771712acd1133078025a0088157d119d924d47413c81b91b9f18ff148623a2ef13dab1895ca3ba546b771a046a021b1e1f64d1a60bb66c19231f641b352326188a9ed3b931b698a939f78d0"
+ // }
+ // },
+ // "address":"0xe0cd26f9A60118555247aE6769A5d241D91f07f2",
+ // "status":"confirmed",
+ // "relay_status":"",
+ // "created_at":"2020-05-05T06:32:19.907061Z",
+ // "cancel_requested":false
+ // }
+ //
+ // withdraw
+ //
+ // {
+ // "code": "initiated",
+ // "id": 3,
+ // "result": "Withdraw initiated. Please allow 3-5 minutes for our system to process."
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (transaction, 'created_at'));
+ const id = this.safeString (transaction, 'id');
+ const networkData = this.safeValue (transaction, 'network_data', {});
+ const unsignedTx = this.safeValue (networkData, 'unsigned_tx', {});
+ const addressFrom = this.safeString (unsignedTx, 'from');
+ const txid = this.safeString (networkData, 'txid');
+ let address = this.safeString (transaction, 'address');
+ let tag = undefined;
+ if (address !== undefined) {
+ const parts = address.split (':');
+ const numParts = parts.length;
+ if (numParts > 1) {
+ address = this.safeString (parts, 0);
+ tag = this.safeString (parts, 1);
+ }
+ }
+ const addressTo = address;
+ const tagFrom = undefined;
+ const tagTo = tag;
+ const cancelRequested = this.safeValue (transaction, 'cancel_requested');
+ const type = (cancelRequested === undefined) ? 'deposit' : 'withdrawal';
+ const amount = this.safeFloat (transaction, 'amount');
+ const currencyId = this.safeString (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ let status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const statusCode = this.safeString (transaction, 'code');
+ if (cancelRequested) {
+ status = 'canceled';
+ } else if (status === undefined) {
+ status = this.parseTransactionStatus (statusCode);
+ }
+ const fee = undefined;
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'addressFrom': addressFrom,
+ 'addressTo': addressTo,
+ 'address': address,
+ 'tagFrom': tagFrom,
+ 'tagTo': tagTo,
+ 'tag': tag,
+ 'type': type,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': undefined,
+ 'fee': fee,
+ };
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'initiated': 'pending',
+ 'needs_create': 'pending',
+ 'credited': 'ok',
+ 'confirmed': 'ok',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'address': address,
+ 'amount': amount,
+ 'currency': currency['id'],
+ };
+ if (tag !== undefined) {
+ request['address'] += ':' + tag;
+ }
+ const response = await this.privatePostWithdraw (this.extend (request, params));
+ //
+ // {
+ // "data": {
+ // "code": "initiated",
+ // "id": 3,
+ // "result": "Withdraw initiated. Please allow 3-5 minutes for our system to process."
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const result = this.parseTransaction (data);
+ return this.extend (result, {
+ 'currency': code,
+ 'address': address,
+ 'addressTo': address,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'amount': amount,
+ });
+ }
+
+ nonce () {
+ return this.milliseconds ();
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let url = '/' + this.version + '/';
+ if (api === 'private') {
+ url += 'user/';
+ }
+ url += this.implodeParams (path, params);
+ const request = this.omit (params, this.extractParams (path));
+ if (method === 'POST') {
+ body = this.json (request);
+ } else {
+ if (Object.keys (request).length) {
+ url += '?' + this.urlencode (request);
+ }
+ }
+ if (api === 'private') {
+ const timestamp = this.milliseconds ().toString ();
+ const bodyAsString = (method === 'POST') ? body : '';
+ const auth = [
+ method,
+ url,
+ timestamp,
+ bodyAsString,
+ this.secret,
+ ].join ("\n"); // eslint-disable-line quotes
+ const hash = this.hash (this.encode (auth), 'sha256', 'base64');
+ let key = this.apiKey;
+ if (typeof key !== 'string') {
+ key = key.toString ();
+ }
+ const signature = 'HMAC-SHA256 ' + key + ':' + hash;
+ headers = {
+ 'Authorization': signature,
+ 'HMAC-Timestamp': timestamp,
+ };
+ if (method === 'POST') {
+ headers['Content-Type'] = 'application/json';
+ }
+ }
+ url = this.urls['api'] + url;
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ //
+ // {"errors":[{"code":"insuff_funds","title":"Your available balance is too low for that action"}]}
+ // {"errors":[{"code": "invalid_auth","title": "Invalid HMAC signature"}]}
+ //
+ if (response === undefined) {
+ return;
+ }
+ const errors = this.safeValue (response, 'errors', []);
+ const numErrors = errors.length;
+ if (numErrors < 1) {
+ return;
+ }
+ const feedback = this.id + ' ' + body;
+ for (let i = 0; i < errors.length; i++) {
+ const error = errors[i];
+ const errorCode = this.safeString (error, 'code');
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ }
+ throw new ExchangeError (feedback); // unknown message
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7}],120:[function(require,module,exports){
'use strict';
const Exchange = require ('./base/Exchange');
@@ -82248,14 +100960,21 @@ module.exports = class rightbtc extends Exchange {
'name': 'RightBTC',
'countries': [ 'AE' ],
'has': {
+ 'cancelOrder': true,
+ 'createOrder': true,
'privateAPI': false,
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'fetchBalance': true,
'fetchClosedOrders': false,
- 'fetchOrder': 'emulated',
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': 'emulated',
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'timeframes': {
'1m': 'min1',
@@ -82267,7 +100986,7 @@ module.exports = class rightbtc extends Exchange {
'1w': 'week',
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/42633917-7d20757e-85ea-11e8-9f53-fffe9fbb7695.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87182092-1f372700-c2ec-11ea-8f9e-01b4d3ff8941.jpg',
'api': 'https://www.rightbtc.com/api',
'www': 'https://www.rightbtc.com',
'doc': [
@@ -82485,7 +101204,7 @@ module.exports = class rightbtc extends Exchange {
const symbol = market['symbol'];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -82541,16 +101260,8 @@ module.exports = class rightbtc extends Exchange {
if (amount !== undefined) {
amount = amount / 1e8;
}
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (trade, 'trading_pair');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (trade, 'trading_pair');
+ const symbol = this.safeSymbol (marketId, market);
let cost = this.costToPrecision (symbol, price * amount);
cost = parseFloat (cost);
let side = this.safeStringLower (trade, 'side');
@@ -82586,9 +101297,9 @@ module.exports = class rightbtc extends Exchange {
return this.parseTrades (response['result'], market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
return [
- parseInt (ohlcv[0]),
+ this.safeInteger (ohlcv, 0),
parseFloat (ohlcv[2]) / 1e8,
parseFloat (ohlcv[3]) / 1e8,
parseFloat (ohlcv[4]) / 1e8,
@@ -82605,7 +101316,8 @@ module.exports = class rightbtc extends Exchange {
'timeSymbol': this.timeframes[timeframe],
};
const response = await this.publicGetCandlestickTimeSymbolTradingPair (this.extend (request, params));
- return this.parseOHLCVs (response['result'], market, timeframe, since, limit);
+ const result = this.safeValue (response, 'result', []);
+ return this.parseOHLCVs (result, market, timeframe, since, limit);
}
async fetchBalance (params = {}) {
@@ -82721,15 +101433,7 @@ module.exports = class rightbtc extends Exchange {
const id = this.safeString (order, 'id');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
const marketId = this.safeString (order, 'trading_pair');
- if (market === undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- let symbol = marketId;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
let timestamp = this.safeInteger (order, 'created');
if (timestamp === undefined) {
timestamp = this.parse8601 (this.safeString (order, 'created_at'));
@@ -82785,8 +101489,10 @@ module.exports = class rightbtc extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'filled': filled,
@@ -82999,12 +101705,960 @@ module.exports = class rightbtc extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9,"./base/functions/number":15}],118:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],121:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
+const { AuthenticationError, ExchangeError, BadSymbol, BadRequest, InvalidOrder, ArgumentsRequired, OrderNotFound, InsufficientFunds, DDoSProtection } = require ('./base/errors');
+const { TICK_SIZE } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class ripio extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'ripio',
+ 'name': 'Ripio',
+ 'countries': [ 'AR', 'BR' ], // Argentina
+ 'rateLimit': 50,
+ 'version': 'v1',
+ 'pro': true,
+ // new metainfo interface
+ 'has': {
+ 'CORS': false,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/94507548-a83d6a80-0218-11eb-9998-28b9cec54165.jpg',
+ 'api': {
+ 'public': 'https://api.exchange.ripio.com/api',
+ 'private': 'https://api.exchange.ripio.com/api',
+ },
+ 'www': 'https://exchange.ripio.com',
+ 'doc': [
+ 'https://exchange.ripio.com/en/api/',
+ ],
+ 'fees': 'https://exchange.ripio.com/en/fee',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'rate/all/',
+ 'rate/{pair}/',
+ 'orderbook/{pair}/',
+ 'tradehistory/{pair}/',
+ 'pair/',
+ 'currency/',
+ 'orderbook/{pair}/depth/',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'balances/exchange_balances/',
+ 'order/{pair}/{order_id}/',
+ 'order/{pair}/',
+ 'trade/{pair}/',
+ ],
+ 'post': [
+ 'order/{pair}/',
+ 'order/{pair}/{order_id}/cancel/',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.0 / 100,
+ 'maker': 0.0 / 100,
+ },
+ },
+ 'precisionMode': TICK_SIZE,
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': false,
+ },
+ 'exceptions': {
+ 'exact': {
+ },
+ 'broad': {
+ 'Authentication credentials were not provided': AuthenticationError, // {"detail":"Authentication credentials were not provided."}
+ 'Disabled pair': BadSymbol, // {"status_code":400,"errors":{"pair":["Invalid/Disabled pair BTC_ARS"]},"message":"An error has occurred, please check the form."}
+ 'Invalid order type': InvalidOrder, // {"status_code":400,"errors":{"order_type":["Invalid order type. Valid options: ['MARKET', 'LIMIT']"]},"message":"An error has occurred, please check the form."}
+ 'Your balance is not enough': InsufficientFunds, // {"status_code":400,"errors":{"non_field_errors":["Your balance is not enough for this order: You have 0 BTC but you need 1 BTC"]},"message":"An error has occurred, please check the form."}
+ "Order couldn't be created": ExchangeError, // {'status_code': 400,'errors': {'non_field_errors': _("Order couldn't be created")}, 'message': _('Seems like an unexpected error occurred. Please try again later or write us to support@ripio.com if the problem persists.') }
+ // {"status_code":404,"errors":{"order":["Order 286e560e-b8a2-464b-8b84-15a7e2a67eab not found."]},"message":"An error has occurred, please check the form."}
+ // {"status_code":404,"errors":{"trade":["Trade not found."]},"message":"An error has occurred, please check the form."}
+ 'not found': OrderNotFound,
+ 'Invalid pair': BadSymbol, // {"status_code":400,"errors":{"pair":["Invalid pair FOOBAR"]},"message":"An error has occurred, please check the form."}
+ 'amount must be a number': BadRequest, // {"status_code":400,"errors":{"amount":["amount must be a number"]},"message":"An error has occurred, please check the form."}
+ 'Total must be at least': InvalidOrder, // {"status_code":400,"errors":{"non_field_errors":["Total must be at least 10."]},"message":"An error has occurred, please check the form."}
+ 'Account not found': BadRequest, // {"error_description": "Account not found."}, "status": 404
+ 'Wrong password provided': AuthenticationError, // {'error': "Wrong password provided."}, “status_code”: 400
+ 'User tokens limit': DDoSProtection, // {'error': "User tokens limit. Can't create more than 10 tokens."}, “status_code”: 400
+ 'Something unexpected ocurred': ExchangeError, // {'status_code': 400, 'errors': {'non_field_errors': 'Something unexpected ocurred!'}, 'message': 'Seems like an unexpected error occurred. Please try again later or write us to support@ripio.com if the problem persists.'}
+ // {'status_code': 404, 'errors': {'account_balance': ['Exchange balance not found.']},'message': 'An error has occurred, please check the form.'}
+ // {'status_code': 404, 'errors': {'account_balance': ['Account balance not found.']},'message': 'An error has occurred, please check the form.'}
+ 'account_balance': BadRequest,
+ },
+ },
+ });
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetPair (params);
+ //
+ // {
+ // "next":null,
+ // "previous":null,
+ // "results":[
+ // {
+ // "base":"BTC",
+ // "base_name":"Bitcoin",
+ // "quote":"USDC",
+ // "quote_name":"USD Coin",
+ // "symbol":"BTC_USDC",
+ // "fees":[
+ // {"traded_volume":0.0,"maker_fee":0.0,"taker_fee":0.0,"cancellation_fee":0.0}
+ // ],
+ // "country":"ZZ",
+ // "enabled":true,
+ // "priority":10,
+ // "min_amount":"0.00001",
+ // "price_tick":"0.000001",
+ // "min_value":"10",
+ // "limit_price_threshold":"25.00"
+ // },
+ // ]
+ // }
+ //
+ const result = [];
+ const results = this.safeValue (response, 'results', []);
+ for (let i = 0; i < results.length; i++) {
+ const market = results[i];
+ const baseId = this.safeString (market, 'base');
+ const quoteId = this.safeString (market, 'quote');
+ const id = this.safeString (market, 'symbol');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const precision = {
+ 'amount': this.safeFloat (market, 'min_amount'),
+ 'price': this.safeFloat (market, 'price_tick'),
+ };
+ const limits = {
+ 'amount': {
+ 'min': this.safeFloat (market, 'min_amount'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': this.safeFloat (market, 'min_value'),
+ 'max': undefined,
+ },
+ };
+ const active = this.safeValue (market, 'enabled', true);
+ const fees = this.safeValue (market, 'fees', []);
+ const firstFee = this.safeValue (fees, 0, {});
+ const maker = this.safeFloat (firstFee, 'maker_fee', 0.0);
+ const taker = this.safeFloat (firstFee, 'taker_fee', 0.0);
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'precision': precision,
+ 'maker': maker,
+ 'taker': taker,
+ 'limits': limits,
+ 'info': market,
+ 'active': active,
+ });
+ }
+ return result;
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCurrency (params);
+ //
+ // {
+ // "next":null,
+ // "previous":null,
+ // "results":[
+ // {
+ // "name":"Argentine Peso",
+ // "symbol":"$",
+ // "currency":"ARS",
+ // "country":"AR",
+ // "decimal_places":"2",
+ // "enabled":true
+ // },
+ // {
+ // "name":"Bitcoin Cash",
+ // "symbol":"BCH",
+ // "currency":"BCH",
+ // "country":"AR",
+ // "decimal_places":"8",
+ // "enabled":true
+ // },
+ // {
+ // "name":"Bitcoin",
+ // "symbol":"BTC",
+ // "currency":"BTC",
+ // "country":"AR",
+ // "decimal_places":"8",
+ // "enabled":true
+ // }
+ // ]
+ // }
+ //
+ const results = this.safeValue (response, 'results', []);
+ const result = {};
+ for (let i = 0; i < results.length; i++) {
+ const currency = results[i];
+ const id = this.safeString (currency, 'currency');
+ const code = this.safeCurrencyCode (id);
+ const name = this.safeString (currency, 'name');
+ const active = this.safeValue (currency, 'enabled', true);
+ const precision = this.safeInteger (currency, 'decimal_places');
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'name': name,
+ 'info': currency, // the original payload
+ 'active': active,
+ 'fee': undefined,
+ 'precision': precision,
+ 'limits': {
+ 'amount': { 'min': undefined, 'max': undefined },
+ 'price': { 'min': undefined, 'max': undefined },
+ 'cost': { 'min': undefined, 'max': undefined },
+ 'withdraw': { 'min': undefined, 'max': undefined },
+ },
+ };
+ }
+ return result;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker, fetchTickers
+ //
+ // {
+ // "pair":"BTC_USDC",
+ // "last_price":"10850.02",
+ // "low":"10720.03",
+ // "high":"10909.99",
+ // "variation":"1.21",
+ // "volume":"0.83868",
+ // "base":"BTC",
+ // "base_name":"Bitcoin",
+ // "quote":"USDC",
+ // "quote_name":"USD Coin",
+ // "bid":"10811.00",
+ // "ask":"10720.03",
+ // "avg":"10851.47",
+ // "ask_volume":"0.00140",
+ // "bid_volume":"0.00185",
+ // "created_at":"2020-09-28 21:44:51.228920+00:00"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (ticker, 'created_at'));
+ const marketId = this.safeString (ticker, 'pair');
+ const symbol = this.safeSymbol (marketId, market);
+ const last = this.safeFloat (ticker, 'last_price');
+ const average = this.safeFloat (ticker, 'avg');
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': this.safeFloat (ticker, 'bid'),
+ 'bidVolume': this.safeFloat (ticker, 'bid_volume'),
+ 'ask': this.safeFloat (ticker, 'ask'),
+ 'askVolume': this.safeFloat (ticker, 'ask_volume'),
+ 'vwap': undefined,
+ 'open': undefined,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': undefined,
+ 'percentage': undefined,
+ 'average': average,
+ 'baseVolume': undefined,
+ 'quoteVolume': undefined,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'pair': market['id'],
+ };
+ const response = await this.publicGetRatePair (this.extend (request, params));
+ //
+ // {
+ // "pair":"BTC_USDC",
+ // "last_price":"10850.02",
+ // "low":"10720.03",
+ // "high":"10909.99",
+ // "variation":"1.21",
+ // "volume":"0.83868",
+ // "base":"BTC",
+ // "base_name":"Bitcoin",
+ // "quote":"USDC",
+ // "quote_name":"USD Coin",
+ // "bid":"10811.00",
+ // "ask":"10720.03",
+ // "avg":"10851.47",
+ // "ask_volume":"0.00140",
+ // "bid_volume":"0.00185",
+ // "created_at":"2020-09-28 21:44:51.228920+00:00"
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetRateAll (params);
+ //
+ // [
+ // {
+ // "pair":"BTC_USDC",
+ // "last_price":"10850.02",
+ // "low":"10720.03",
+ // "high":"10909.99",
+ // "variation":"1.21",
+ // "volume":"0.83868",
+ // "base":"BTC",
+ // "base_name":"Bitcoin",
+ // "quote":"USDC",
+ // "quote_name":"USD Coin",
+ // "bid":"10811.00",
+ // "ask":"10720.03",
+ // "avg":"10851.47",
+ // "ask_volume":"0.00140",
+ // "bid_volume":"0.00185",
+ // "created_at":"2020-09-28 21:44:51.228920+00:00"
+ // }
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const ticker = this.parseTicker (response[i]);
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'pair': this.marketId (symbol),
+ };
+ const response = await this.publicGetOrderbookPair (this.extend (request, params));
+ //
+ // {
+ // "buy":[
+ // {"amount":"0.00230","total":"24.95","price":"10850.02"},
+ // {"amount":"0.07920","total":"858.52","price":"10840.00"},
+ // {"amount":"0.00277","total":"30.00","price":"10833.03"},
+ // ],
+ // "sell":[
+ // {"amount":"0.03193","total":"348.16","price":"10904.00"},
+ // {"amount":"0.00210","total":"22.90","price":"10905.70"},
+ // {"amount":"0.00300","total":"32.72","price":"10907.98"},
+ // ],
+ // "updated_id":47225
+ // }
+ //
+ const orderbook = this.parseOrderBook (response, undefined, 'buy', 'sell', 'price', 'amount');
+ orderbook['nonce'] = this.safeInteger (response, 'updated_id');
+ return orderbook;
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades, private fetchMyTrades
+ //
+ // {
+ // "created_at":1601322501,
+ // "amount":"0.00276",
+ // "price":"10850.020000",
+ // "side":"SELL",
+ // "pair":"BTC_USDC",
+ // "taker_fee":"0",
+ // "taker_side":"SELL",
+ // "maker_fee":"0",
+ // "taker":2577953,
+ // "maker":2577937
+ // }
+ //
+ // createOrder fills
+ //
+ // {
+ // "pair":"BTC_USDC",
+ // "exchanged":0.002,
+ // "match_price":10593.99,
+ // "maker_fee":0.0,
+ // "taker_fee":0.0,
+ // "timestamp":1601730306942
+ // }
+ //
+ const id = this.safeString (trade, 'id');
+ let timestamp = this.safeInteger (trade, 'timestamp');
+ timestamp = this.safeTimestamp (trade, 'created_at', timestamp);
+ let side = this.safeString (trade, 'side');
+ const takerSide = this.safeString (trade, 'taker_side');
+ const takerOrMaker = (takerSide === side) ? 'taker' : 'maker';
+ if (side !== undefined) {
+ side = side.toLowerCase ();
+ }
+ const price = this.safeFloat2 (trade, 'price', 'match_price');
+ const amount = this.safeFloat2 (trade, 'amount', 'exchanged');
+ let cost = undefined;
+ if ((amount !== undefined) && (price !== undefined)) {
+ cost = amount * price;
+ }
+ const marketId = this.safeString (trade, 'pair');
+ market = this.safeMarket (marketId, market);
+ const feeCost = this.safeFloat (trade, takerOrMaker + '_fee');
+ const orderId = this.safeString (trade, takerOrMaker);
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': (side === 'buy') ? market['base'] : market['quote'],
+ };
+ }
+ return {
+ 'id': id,
+ 'order': orderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': market['symbol'],
+ 'type': undefined,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'takerOrMaker': takerOrMaker,
+ 'fee': fee,
+ 'info': trade,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'pair': market['id'],
+ };
+ const response = await this.publicGetTradehistoryPair (this.extend (request, params));
+ //
+ // [
+ // {
+ // "created_at":1601322501,
+ // "amount":"0.00276",
+ // "price":"10850.020000",
+ // "side":"SELL",
+ // "pair":"BTC_USDC",
+ // "taker_fee":"0",
+ // "taker_side":"SELL",
+ // "maker_fee":"0",
+ // "taker":2577953,
+ // "maker":2577937
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetBalancesExchangeBalances (params);
+ //
+ // [
+ // {
+ // "id":603794,
+ // "currency":"USD Coin",
+ // "symbol":"USDC",
+ // "available":"0",
+ // "locked":"0",
+ // "code":"exchange",
+ // "balance_type":"crypto"
+ // },
+ // ]
+ //
+ const result = { 'info': response };
+ for (let i = 0; i < response.length; i++) {
+ const balance = response[i];
+ const currencyId = this.safeString (balance, 'symbol');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['free'] = this.safeFloat (balance, 'available');
+ account['used'] = this.safeFloat (balance, 'locked');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const uppercaseType = type.toUpperCase ();
+ const uppercaseSide = side.toUpperCase ();
+ const request = {
+ 'pair': market['id'],
+ 'order_type': uppercaseType, // LIMIT, MARKET
+ 'side': uppercaseSide, // BUY or SELL
+ 'amount': this.amountToPrecision (symbol, amount),
+ };
+ if (uppercaseType === 'LIMIT') {
+ request['limit_price'] = this.priceToPrecision (symbol, price);
+ }
+ const response = await this.privatePostOrderPair (this.extend (request, params));
+ //
+ // {
+ // "order_id": "160f523c-f6ef-4cd1-a7c9-1a8ede1468d8",
+ // "pair": "BTC_ARS",
+ // "side": "BUY",
+ // "amount": "0.00400",
+ // "notional": null,
+ // "fill_or_kill": false,
+ // "all_or_none": false,
+ // "order_type": "LIMIT",
+ // "status": "OPEN",
+ // "created_at": 1578413945,
+ // "filled": "0.00000",
+ // "limit_price": "10.00",
+ // "stop_price": null,
+ // "distance": null
+ // }
+ //
+ // createOrder market type
+ //
+ // {
+ // "order_id":"d6b60c01-8624-44f2-9e6c-9e8cd677ea5c",
+ // "pair":"BTC_USDC",
+ // "side":"BUY",
+ // "amount":"0.00200",
+ // "notional":"50",
+ // "fill_or_kill":false,
+ // "all_or_none":false,
+ // "order_type":"MARKET",
+ // "status":"OPEN",
+ // "created_at":1601730306,
+ // "filled":"0.00000",
+ // "fill_price":10593.99,
+ // "fee":0.0,
+ // "fills":[
+ // {
+ // "pair":"BTC_USDC",
+ // "exchanged":0.002,
+ // "match_price":10593.99,
+ // "maker_fee":0.0,
+ // "taker_fee":0.0,
+ // "timestamp":1601730306942
+ // }
+ // ],
+ // "filled_at":"2020-10-03T13:05:06.942186Z",
+ // "limit_price":"0.000000",
+ // "stop_price":null,
+ // "distance":null
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder() requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'pair': market['id'],
+ 'order_id': id,
+ };
+ const response = await this.privatePostOrderPairOrderIdCancel (this.extend (request, params));
+ //
+ // {
+ // "order_id": "286e560e-b8a2-464b-8b84-15a7e2a67eab",
+ // "pair": "BTC_ARS",
+ // "side": "SELL",
+ // "amount": "0.00100",
+ // "notional": null,
+ // "fill_or_kill": false,
+ // "all_or_none": false,
+ // "order_type": "LIMIT",
+ // "status": "CANC",
+ // "created_at": 1575472707,
+ // "filled": "0.00000",
+ // "limit_price": "681000.00",
+ // "stop_price": null,
+ // "distance": null
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrder() requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'pair': market['id'],
+ 'order_id': id,
+ };
+ const response = await this.privateGetOrderPairOrderId (this.extend (request, params));
+ //
+ // {
+ // "order_id": "0b4ff48e-cfd6-42db-8d8c-3b536da447af",
+ // "pair": "BTC_ARS",
+ // "side": "BUY",
+ // "amount": "0.00100",
+ // "notional": null,
+ // "fill_or_kill": false,
+ // "all_or_none": false,
+ // "order_type": "LIMIT",
+ // "status": "OPEN",
+ // "created_at": 1575472944,
+ // "filled": "0.00000",
+ // "limit_price": "661000.00",
+ // "stop_price": null,
+ // "distance": null
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrders() requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'pair': market['id'],
+ // 'status': 'OPEN,PART,CLOS,CANC,COMP',
+ // 'offset': 0,
+ // 'limit': limit,
+ };
+ if (limit !== undefined) {
+ request['offset'] = limit;
+ }
+ const response = await this.privateGetOrderPair (this.extend (request, params));
+ //
+ // {
+ // "next": "https://api.exchange.ripio.com/api/v1/order/BTC_ARS/?limit=20&offset=20&page=1&page_size=25&status=OPEN%2CPART",
+ // "previous": null,
+ // "results": {
+ // "data": [
+ // {
+ // "order_id": "ca74280b-6966-4b73-a720-68709078922b",
+ // "pair": "BTC_ARS",
+ // "side": "SELL",
+ // "amount": "0.00100",
+ // "notional": null,
+ // "fill_or_kill": false,
+ // "all_or_none": false,
+ // "order_type": "LIMIT",
+ // "status": "OPEN",
+ // "created_at": 1578340134,
+ // "filled": "0.00000",
+ // "limit_price": "665000.00",
+ // "stop_price": null,
+ // "distance": null
+ // },
+ // ]
+ // }
+ // }
+ //
+ const results = this.safeValue (response, 'results', {});
+ const data = this.safeValue (results, 'data', []);
+ return this.parseOrders (data, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'status': 'OPEN,PART',
+ };
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'status': 'CLOS,CANC,COMP',
+ };
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'OPEN': 'open',
+ 'PART': 'open',
+ 'CLOS': 'canceled',
+ 'CANC': 'canceled',
+ 'COMP': 'closed',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder, cancelOrder, fetchOpenOrders, fetchClosedOrders, fetchOrders, fetchOrder
+ //
+ // {
+ // "order_id": "286e560e-b8a2-464b-8b84-15a7e2a67eab",
+ // "pair": "BTC_ARS",
+ // "side": "SELL",
+ // "amount": "0.00100",
+ // "notional": null,
+ // "fill_or_kill": false,
+ // "all_or_none": false,
+ // "order_type": "LIMIT",
+ // "status": "CANC",
+ // "created_at": 1575472707,
+ // "filled": "0.00000",
+ // "limit_price": "681000.00",
+ // "stop_price": null,
+ // "distance": null
+ // }
+ //
+ // {
+ // "order_id":"d6b60c01-8624-44f2-9e6c-9e8cd677ea5c",
+ // "pair":"BTC_USDC",
+ // "side":"BUY",
+ // "amount":"0.00200",
+ // "notional":"50",
+ // "fill_or_kill":false,
+ // "all_or_none":false,
+ // "order_type":"MARKET",
+ // "status":"OPEN",
+ // "created_at":1601730306,
+ // "filled":"0.00000",
+ // "fill_price":10593.99,
+ // "fee":0.0,
+ // "fills":[
+ // {
+ // "pair":"BTC_USDC",
+ // "exchanged":0.002,
+ // "match_price":10593.99,
+ // "maker_fee":0.0,
+ // "taker_fee":0.0,
+ // "timestamp":1601730306942
+ // }
+ // ],
+ // "filled_at":"2020-10-03T13:05:06.942186Z",
+ // "limit_price":"0.000000",
+ // "stop_price":null,
+ // "distance":null
+ // }
+ //
+ const id = this.safeString (order, 'order_id');
+ const amount = this.safeFloat (order, 'amount');
+ let cost = this.safeFloat (order, 'notional');
+ const type = this.safeStringLower (order, 'order_type');
+ const priceField = (type === 'market') ? 'fill_price' : 'limit_price';
+ const price = this.safeFloat (order, priceField);
+ const side = this.safeStringLower (order, 'side');
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const timestamp = this.safeTimestamp (order, 'created_at');
+ let average = this.safeValue (order, 'fill_price');
+ let filled = this.safeFloat (order, 'filled');
+ let remaining = undefined;
+ const fills = this.safeValue (order, 'fills');
+ let trades = undefined;
+ let lastTradeTimestamp = undefined;
+ if (fills !== undefined) {
+ const numFills = fills.length;
+ if (numFills > 0) {
+ filled = 0;
+ cost = 0;
+ trades = this.parseTrades (fills, market, undefined, undefined, {
+ 'order': id,
+ 'side': side,
+ });
+ for (let i = 0; i < trades.length; i++) {
+ const trade = trades[i];
+ filled = this.sum (trade['amount'], filled);
+ cost = this.sum (trade['cost'], cost);
+ lastTradeTimestamp = trade['timestamp'];
+ }
+ if ((average === undefined) && (filled > 0)) {
+ average = cost / filled;
+ }
+ }
+ }
+ if (filled !== undefined) {
+ if ((cost === undefined) && (price !== undefined)) {
+ cost = price * filled;
+ }
+ if (amount !== undefined) {
+ remaining = Math.max (0, amount - filled);
+ }
+ }
+ const marketId = this.safeString (order, 'pair');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const stopPrice = this.safeFloat (order, 'stop_price');
+ return {
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'info': order,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': stopPrice,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': undefined,
+ 'trades': trades,
+ };
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades() requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'pair': market['id'],
+ // 'offset': 0,
+ // 'limit': limit,
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetTradePair (this.extend (request, params));
+ //
+ // {
+ // "next": "https://api.exchange.ripio.com/api/v1/trade//?limit=20&offset=20",
+ // "previous": null,
+ // "results": {
+ // "data": [
+ // {
+ // "created_at": 1578414028,
+ // "amount": "0.00100",
+ // "price": "665000.00",
+ // "side": "BUY",
+ // "taker_fee": "0",
+ // "taker_side": "BUY",
+ // "match_price": "66500000",
+ // "maker_fee": "0",
+ // "taker": 4892,
+ // "maker": 4889
+ // },
+ // ]
+ // }
+ // }
+ //
+ const results = this.safeValue (response, 'results', {});
+ const data = this.safeValue (results, 'data', []);
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const request = '/' + this.version + '/' + this.implodeParams (path, params);
+ let url = this.urls['api'][api] + request;
+ const query = this.omit (params, this.extractParams (path));
+ if (api === 'public') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (api === 'private') {
+ this.checkRequiredCredentials ();
+ if (method === 'POST') {
+ body = this.json (query);
+ } else {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ }
+ headers = {
+ 'Content-Type': 'application/json',
+ 'Authorization': 'Bearer ' + this.apiKey,
+ };
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return;
+ }
+ //
+ // {"detail":"Authentication credentials were not provided."}
+ // {"status_code":400,"errors":{"pair":["Invalid pair FOOBAR"]},"message":"An error has occurred, please check the form."}
+ // {"status_code":400,"errors":{"order_type":["Invalid order type. Valid options: ['MARKET', 'LIMIT']"]},"message":"An error has occurred, please check the form."}
+ // {"status_code":400,"errors":{"non_field_errors":"Something unexpected ocurred!"},"message":"Seems like an unexpected error occurred. Please try again later or write us to support@ripio.com if the problem persists."}
+ // {"status_code":400,"errors":{"pair":["Invalid/Disabled pair BTC_ARS"]},"message":"An error has occurred, please check the form."}
+ //
+ const detail = this.safeString (response, 'detail');
+ if (detail !== undefined) {
+ const feedback = this.id + ' ' + body;
+ // this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], detail, feedback);
+ }
+ const errors = this.safeValue (response, 'errors');
+ if (errors !== undefined) {
+ const feedback = this.id + ' ' + body;
+ const keys = Object.keys (errors);
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i];
+ const error = this.safeValue (errors, key, []);
+ const message = this.safeString (error, 0);
+ // this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ }
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],122:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ArgumentsRequired } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -83016,10 +102670,21 @@ module.exports = class southxchange extends Exchange {
'countries': [ 'AR' ], // Argentina
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': true,
'createDepositAddress': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
+ 'fetchWithdrawals': true,
'withdraw': true,
},
'urls': {
@@ -83061,9 +102726,10 @@ module.exports = class southxchange extends Exchange {
},
},
'commonCurrencies': {
- 'SMT': 'SmartNode',
- 'MTC': 'Marinecoin',
'BHD': 'Bithold',
+ 'GHOST': 'GHOSTPRISM',
+ 'MTC': 'Marinecoin',
+ 'SMT': 'SmartNode',
},
});
}
@@ -83161,16 +102827,12 @@ module.exports = class southxchange extends Exchange {
const result = {};
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- let symbol = id;
- let market = undefined;
- if (id in this.markets_by_id) {
- market = this.markets_by_id[id];
- symbol = market['symbol'];
- }
+ const market = this.safeMarket (id);
+ const symbol = market['symbol'];
const ticker = tickers[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -83256,8 +102918,10 @@ module.exports = class southxchange extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'filled': filled,
@@ -83293,9 +102957,10 @@ module.exports = class southxchange extends Exchange {
request['limitPrice'] = price;
}
const response = await this.privatePostPlaceOrder (this.extend (request, params));
+ const id = JSON.parse (response);
return {
'info': response,
- 'id': response.toString (),
+ 'id': id,
};
}
@@ -83314,9 +102979,21 @@ module.exports = class southxchange extends Exchange {
'currency': currency['id'],
};
const response = await this.privatePostGeneratenewaddress (this.extend (request, params));
- const parts = response.split ('|');
+ //
+ // the exchange API returns a quoted-quoted-string
+ //
+ // "\"0x4d43674209fcb66cc21469a6e5e52de7dd5bcd93\""
+ //
+ let address = response;
+ if (address[0] === '"') {
+ address = JSON.parse (address);
+ if (address[0] === '"') {
+ address = JSON.parse (address);
+ }
+ }
+ const parts = address.split ('|');
const numParts = parts.length;
- const address = parts[0];
+ address = parts[0];
this.checkAddress (address);
let tag = undefined;
if (numParts > 1) {
@@ -83349,6 +103026,311 @@ module.exports = class southxchange extends Exchange {
};
}
+ parseLedgerEntryType (type) {
+ const types = {
+ 'trade': 'trade',
+ 'tradefee': 'fee',
+ 'withdraw': 'transaction',
+ 'deposit': 'transaction',
+ };
+ return this.safeString (types, type, type);
+ }
+
+ parseLedgerEntry (item, currency = undefined) {
+ //
+ // {
+ // "Date":"2020-08-07T12:36:52.72",
+ // "CurrencyCode":"USDT",
+ // "Amount":27.614678000000000000,
+ // "TotalBalance":27.614678000000000000,
+ // "Type":"deposit",
+ // "Status":"confirmed",
+ // "Address":"0x4d43674209fcb66cc21469a6e5e52de7dd5bcd93",
+ // "Hash":"0x1809f1950c51a2f64fd2c4a27d4b06450fd249883fd91c852b79a99a124837f3",
+ // "Price":0.0,
+ // "OtherAmount":0.0,
+ // "OtherCurrency":null,
+ // "OrderCode":null,
+ // "TradeId":null,
+ // "MovementId":2732259
+ // }
+ //
+ const id = this.safeString (item, 'MovementId');
+ let direction = undefined;
+ const account = undefined;
+ let referenceId = this.safeString2 (item, 'TradeId', 'OrderCode');
+ referenceId = this.safeString (item, 'Hash', referenceId);
+ const referenceAccount = this.safeString (item, 'Address');
+ const type = this.safeString (item, 'Type');
+ const ledgerEntryType = this.parseLedgerEntryType (type);
+ const code = this.safeCurrencyCode (this.safeString (item, 'CurrencyCode'), currency);
+ let amount = this.safeFloat (item, 'Amount');
+ const after = this.safeFloat (item, 'TotalBalance');
+ let before = undefined;
+ if (amount !== undefined) {
+ if (after !== undefined) {
+ before = after - amount;
+ }
+ if (type === 'withdrawal') {
+ direction = 'out';
+ } else if (type === 'deposit') {
+ direction = 'in';
+ } else if ((type === 'trade') || (type === 'tradefee')) {
+ direction = (amount < 0) ? 'out' : 'in';
+ amount = Math.abs (amount);
+ }
+ }
+ const timestamp = this.parse8601 (this.safeString (item, 'Date'));
+ const fee = undefined;
+ const status = this.safeString (item, 'Status');
+ return {
+ 'info': item,
+ 'id': id,
+ 'direction': direction,
+ 'account': account,
+ 'referenceId': referenceId,
+ 'referenceAccount': referenceAccount,
+ 'type': ledgerEntryType,
+ 'currency': code,
+ 'amount': amount,
+ 'before': before,
+ 'after': after,
+ 'status': status,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': fee,
+ };
+ }
+
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchLedger() requires a code argument');
+ }
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ limit = (limit === undefined) ? 50 : limit;
+ const request = {
+ 'Currency': currency['id'],
+ // 'TransactionType': 'transactions', // deposits, withdrawals, depositswithdrawals, transactions
+ // 'PageIndex': 0,
+ 'PageSize': limit, // max 50
+ 'SortField': 'Date',
+ // 'Descending': true,
+ };
+ const pageIndex = this.safeInteger (params, 'PageIndex');
+ if (pageIndex === undefined) {
+ request['Descending'] = true;
+ }
+ const response = await this.privatePostListTransactions (this.extend (request, params));
+ //
+ // fetchLedger ('BTC')
+ //
+ // {
+ // "TotalElements":2,
+ // "Result":[
+ // {
+ // "Date":"2020-08-07T13:06:22.117",
+ // "CurrencyCode":"BTC",
+ // "Amount":-0.000000301000000000,
+ // "TotalBalance":0.000100099000000000,
+ // "Type":"tradefee",
+ // "Status":"confirmed",
+ // "Address":null,
+ // "Hash":null,
+ // "Price":0.0,
+ // "OtherAmount":0.0,
+ // "OtherCurrency":null,
+ // "OrderCode":null,
+ // "TradeId":5298215,
+ // "MovementId":null
+ // },
+ // {
+ // "Date":"2020-08-07T13:06:22.117",
+ // "CurrencyCode":"BTC",
+ // "Amount":0.000100400000000000,
+ // "TotalBalance":0.000100400000000000,
+ // "Type":"trade",
+ // "Status":"confirmed",
+ // "Address":null,
+ // "Hash":null,
+ // "Price":11811.474849000000000000,
+ // "OtherAmount":1.185872,
+ // "OtherCurrency":"USDT",
+ // "OrderCode":"78389610",
+ // "TradeId":5298215,
+ // "MovementId":null
+ // }
+ // ]
+ // }
+ //
+ // fetchLedger ('BTC'), same trade, other side
+ //
+ // {
+ // "TotalElements":2,
+ // "Result":[
+ // {
+ // "Date":"2020-08-07T13:06:22.133",
+ // "CurrencyCode":"USDT",
+ // "Amount":-1.185872000000000000,
+ // "TotalBalance":26.428806000000000000,
+ // "Type":"trade",
+ // "Status":"confirmed",
+ // "Address":null,
+ // "Hash":null,
+ // "Price":11811.474849000000000000,
+ // "OtherAmount":0.000100400,
+ // "OtherCurrency":"BTC",
+ // "OrderCode":"78389610",
+ // "TradeId":5298215,
+ // "MovementId":null
+ // },
+ // {
+ // "Date":"2020-08-07T12:36:52.72",
+ // "CurrencyCode":"USDT",
+ // "Amount":27.614678000000000000,
+ // "TotalBalance":27.614678000000000000,
+ // "Type":"deposit",
+ // "Status":"confirmed",
+ // "Address":"0x4d43674209fcb66cc21469a6e5e52de7dd5bcd93",
+ // "Hash":"0x1809f1950c51a2f64fd2c4a27d4b06450fd249883fd91c852b79a99a124837f3",
+ // "Price":0.0,
+ // "OtherAmount":0.0,
+ // "OtherCurrency":null,
+ // "OrderCode":null,
+ // "TradeId":null,
+ // "MovementId":2732259
+ // }
+ // ]
+ // }
+ //
+ const result = this.safeValue (response, 'Result', []);
+ return this.parseLedger (result, currency, since, limit);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'pending': 'pending',
+ 'processed': 'pending',
+ 'confirmed': 'ok',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // {
+ // "Date":"2020-08-07T12:36:52.72",
+ // "CurrencyCode":"USDT",
+ // "Amount":27.614678000000000000,
+ // "TotalBalance":27.614678000000000000,
+ // "Type":"deposit",
+ // "Status":"confirmed",
+ // "Address":"0x4d43674209fcb66cc21469a6e5e52de7dd5bcd93",
+ // "Hash":"0x1809f1950c51a2f64fd2c4a27d4b06450fd249883fd91c852b79a99a124837f3",
+ // "Price":0.0,
+ // "OtherAmount":0.0,
+ // "OtherCurrency":null,
+ // "OrderCode":null,
+ // "TradeId":null,
+ // "MovementId":2732259
+ // }
+ //
+ const id = this.safeString (transaction, 'MovementId');
+ const amount = this.safeFloat (transaction, 'Amount');
+ const address = this.safeString (transaction, 'Address');
+ const addressTo = address;
+ const addressFrom = undefined;
+ const tag = undefined;
+ const tagTo = tag;
+ const tagFrom = undefined;
+ const txid = this.safeString (transaction, 'Hash');
+ const type = this.safeString (transaction, 'Type');
+ const timestamp = this.parse8601 (this.safeString (transaction, 'Date'));
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'Status'));
+ const currencyId = this.safeString (transaction, 'CurrencyCode');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': code,
+ 'amount': amount,
+ 'address': address,
+ 'addressTo': addressTo,
+ 'addressFrom': addressFrom,
+ 'tag': tag,
+ 'tagTo': tagTo,
+ 'tagFrom': tagFrom,
+ 'status': status,
+ 'type': type,
+ 'updated': undefined,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': undefined,
+ };
+ }
+
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchTransactions() requires a code argument');
+ }
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ limit = (limit === undefined) ? 50 : limit;
+ const request = {
+ 'Currency': currency['id'],
+ 'TransactionType': 'depositswithdrawals', // deposits, withdrawals, depositswithdrawals, transactions
+ // 'PageIndex': 0,
+ 'PageSize': limit, // max 50
+ 'SortField': 'Date',
+ // 'Descending': true,
+ };
+ const pageIndex = this.safeInteger (params, 'PageIndex');
+ if (pageIndex === undefined) {
+ request['Descending'] = true;
+ }
+ const response = await this.privatePostListTransactions (this.extend (request, params));
+ //
+ // {
+ // "TotalElements":2,
+ // "Result":[
+ // {
+ // "Date":"2020-08-07T12:36:52.72",
+ // "CurrencyCode":"USDT",
+ // "Amount":27.614678000000000000,
+ // "TotalBalance":27.614678000000000000,
+ // "Type":"deposit",
+ // "Status":"confirmed",
+ // "Address":"0x4d43674209fcb66cc21469a6e5e52de7dd5bcd93",
+ // "Hash":"0x1809f1950c51a2f64fd2c4a27d4b06450fd249883fd91c852b79a99a124837f3",
+ // "Price":0.0,
+ // "OtherAmount":0.0,
+ // "OtherCurrency":null,
+ // "OrderCode":null,
+ // "TradeId":null,
+ // "MovementId":2732259
+ // }
+ // ]
+ // }
+ //
+ const result = this.safeValue (response, 'Result', []);
+ return this.parseTransactions (result, currency, since, limit);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'TransactionType': 'deposits',
+ };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'TransactionType': 'withdrawals',
+ };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
const url = this.urls['api'] + '/' + this.implodeParams (path, params);
let query = this.omit (params, this.extractParams (path));
@@ -83369,7 +103351,7 @@ module.exports = class southxchange extends Exchange {
}
};
-},{"./base/Exchange":7}],119:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],123:[function(require,module,exports){
(function (module, exports) {
'use strict';
@@ -86897,7 +106879,7 @@ module.exports = class southxchange extends Exchange {
};
})(typeof module === 'undefined' || module, this);
-},{"buffer":178}],120:[function(require,module,exports){
+},{"buffer":185}],124:[function(require,module,exports){
;(function (root, factory) {
if (typeof exports === "object") {
// CommonJS
@@ -92886,7 +112868,7 @@ module.exports = class southxchange extends Exchange {
return CryptoJS;
}));
-},{}],121:[function(require,module,exports){
+},{}],125:[function(require,module,exports){
'use strict';
var elliptic = exports;
@@ -92908,8 +112890,9 @@ elliptic.curves = require('./elliptic/curves');
// Protocols
elliptic.ec = require('./elliptic/ec');
+elliptic.eddsa = require('./elliptic/eddsa');
-},{"./elliptic/curve":124,"./elliptic/curves":127,"./elliptic/ec":128,"./elliptic/utils":132}],122:[function(require,module,exports){
+},{"./elliptic/curve":128,"./elliptic/curves":131,"./elliptic/ec":132,"./elliptic/eddsa":135,"./elliptic/utils":139}],126:[function(require,module,exports){
'use strict';
var BN = require('../../../../BN/bn');
@@ -93286,7 +113269,7 @@ BasePoint.prototype.dblp = function dblp(k) {
return r;
};
-},{"../../../../BN/bn":119,"../../elliptic":121}],123:[function(require,module,exports){
+},{"../../../../BN/bn":123,"../../elliptic":125}],127:[function(require,module,exports){
'use strict';
var curve = require('../curve');
@@ -93721,7 +113704,7 @@ Point.prototype.eqXToP = function eqXToP(x) {
Point.prototype.toP = Point.prototype.normalize;
Point.prototype.mixedAdd = Point.prototype.add;
-},{"../../../../BN/bn":119,"../../elliptic":121,"../curve":124}],124:[function(require,module,exports){
+},{"../../../../BN/bn":123,"../../elliptic":125,"../curve":128}],128:[function(require,module,exports){
'use strict';
var curve = exports;
@@ -93731,7 +113714,7 @@ curve.short = require('./short');
curve.mont = require('./mont');
curve.edwards = require('./edwards');
-},{"./base":122,"./edwards":123,"./mont":125,"./short":126}],125:[function(require,module,exports){
+},{"./base":126,"./edwards":127,"./mont":129,"./short":130}],129:[function(require,module,exports){
'use strict';
var curve = require('../curve');
@@ -93913,7 +113896,7 @@ Point.prototype.getX = function getX() {
return this.x.fromRed();
};
-},{"../../../../BN/bn":119,"../../elliptic":121,"../curve":124}],126:[function(require,module,exports){
+},{"../../../../BN/bn":123,"../../elliptic":125,"../curve":128}],130:[function(require,module,exports){
'use strict';
var curve = require('../curve');
@@ -94853,7 +114836,7 @@ JPoint.prototype.isInfinity = function isInfinity() {
return this.z.cmpn(0) === 0;
};
-},{"../../../../BN/bn":119,"../../elliptic":121,"../curve":124}],127:[function(require,module,exports){
+},{"../../../../BN/bn":123,"../../elliptic":125,"../curve":128}],131:[function(require,module,exports){
'use strict';
var curves = exports;
@@ -95059,7 +115042,7 @@ defineCurve('secp256k1', {
]
});
-},{"../elliptic":121,"./precomputed/secp256k1":131}],128:[function(require,module,exports){
+},{"../elliptic":125,"./precomputed/secp256k1":138}],132:[function(require,module,exports){
'use strict';
var BN = require('../../../../BN/bn');
@@ -95301,7 +115284,7 @@ EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) {
throw new Error('Unable to find valid recovery factor');
};
-},{"../../../../BN/bn":119,"../../elliptic":121,"../../hmac-drbg/hmac-drbg":133,"./key":129,"./signature":130}],129:[function(require,module,exports){
+},{"../../../../BN/bn":123,"../../elliptic":125,"../../hmac-drbg/hmac-drbg":140,"./key":133,"./signature":134}],133:[function(require,module,exports){
'use strict';
var BN = require('../../../../BN/bn');
@@ -95422,7 +115405,7 @@ KeyPair.prototype.inspect = function inspect() {
' pub: ' + (this.pub && this.pub.inspect()) + ' >';
};
-},{"../../../../BN/bn":119,"../../elliptic":121}],130:[function(require,module,exports){
+},{"../../../../BN/bn":123,"../../elliptic":125}],134:[function(require,module,exports){
'use strict';
var BN = require('../../../../BN/bn');
@@ -95448,7 +115431,323 @@ function Signature(options, enc) {
}
module.exports = Signature;
-},{"../../../../BN/bn":119,"../../elliptic":121}],131:[function(require,module,exports){
+},{"../../../../BN/bn":123,"../../elliptic":125}],135:[function(require,module,exports){
+'use strict';
+
+var curves = require('../curves');
+var utils = require('../utils');
+var assert = utils.assert;
+var parseBytes = utils.parseBytes;
+var KeyPair = require('./key');
+var Signature = require('./signature');
+const BN = require ('../../../../BN/bn.js')
+const { byteArrayToWordArray } = require ('../../../../../base/functions/encode')
+const CryptoJS = require('../../../../crypto-js/crypto-js');
+
+
+function EDDSA(curveName) {
+ assert(curveName === 'ed25519', 'only tested with ed25519 so far');
+
+ if (!(this instanceof EDDSA))
+ return new EDDSA(curveName);
+
+ var curve = curves[curveName].curve;
+ this.curve = curve;
+ this.g = curve.g;
+ this.g.precompute(curve.n.bitLength() + 1);
+
+ this.pointClass = curve.point().constructor;
+ this.encodingLength = Math.ceil(curve.n.bitLength() / 8);
+ //this.hash = hash.sha512;
+}
+
+module.exports = EDDSA;
+
+/**
+* @param {Array|String} message - message bytes
+* @param {Array|String|KeyPair} secret - secret bytes or a keypair
+* @returns {Signature} - signature
+*/
+EDDSA.prototype.sign = function sign(message, secret) {
+ message = parseBytes(message);
+ var key = this.keyFromSecret(secret);
+ var r = this.hashInt(key.secret (), message);
+ var R = this.g.mul(r);
+ var Rencoded = this.encodePoint(R);
+ var s_ = this.hashInt(Rencoded, key.pubBytes(), message)
+ s_ = s_.mul (key.priv ())
+ var S = r.add(s_).umod(this.curve.n);
+ return this.makeSignature({ R: R, S: S, Rencoded: Rencoded });
+};
+
+/**
+ * @param {Array|String} message - message bytes
+ * @param {Array|String|KeyPair} secret - secret bytes or a keypair
+ * @returns {Signature} - signature
+ */
+EDDSA.prototype.signModified = function sign(message, secret) {
+ message = parseBytes(message);
+ var key = this.keyFromSecret(secret);
+ // convert between curve25519 and ed25519 keys
+ const secretLE = new BN (key.secret (), 16, 'le')
+ const pubKey = this.encodePoint (this.g.mul (secretLE))
+ const signBit = pubKey[31] & 0x80
+ var r = this.hashInt (key.secret (), message)
+ var R = this.g.mul(r);
+ var Rencoded = this.encodePoint (R);
+ let s_ = this.hashInt (Rencoded, pubKey, message)
+ s_ = s_.mul (secretLE)
+ var S = r.add(s_).umod(this.curve.n);
+ var Sencoded = S.toArray ('le')
+ Sencoded[31] |= signBit
+ return this.makeSignature({ R: R, S: S, Rencoded: Rencoded, Sencoded: Sencoded });
+};
+
+
+/**
+* @param {Array} message - message bytes
+* @param {Array|String|Signature} sig - sig bytes
+* @param {Array|String|Point|KeyPair} pub - public key
+* @returns {Boolean} - true if public key matches sig of message
+*/
+EDDSA.prototype.verify = function verify(message, sig, pub) {
+ message = parseBytes(message);
+ sig = this.makeSignature(sig);
+ var key = this.keyFromPublic(pub);
+ var h = this.hashInt(sig.Rencoded(), key.pubBytes(), message);
+ var SG = this.g.mul(sig.S());
+ var RplusAh = sig.R().add(key.pub().mul(h));
+ return RplusAh.eq(SG);
+};
+
+EDDSA.prototype.hashInt = function hashInt() {
+ let toHash = Array.from (arguments).reduce ((a, b) => a.concat (b))
+ toHash = byteArrayToWordArray (toHash)
+ const digest = CryptoJS['SHA512'] (toHash).toString (CryptoJS.enc.Hex)
+ return utils.intFromLE(digest).umod(this.curve.n);
+};
+
+EDDSA.prototype.keyFromPublic = function keyFromPublic(pub) {
+ return KeyPair.fromPublic(this, pub);
+};
+
+EDDSA.prototype.keyFromSecret = function keyFromSecret(secret) {
+ return KeyPair.fromSecret(this, secret);
+};
+
+EDDSA.prototype.makeSignature = function makeSignature(sig) {
+ if (sig instanceof Signature)
+ return sig;
+ return new Signature(this, sig);
+};
+
+/**
+* * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2
+*
+* EDDSA defines methods for encoding and decoding points and integers. These are
+* helper convenience methods, that pass along to utility functions implied
+* parameters.
+*
+*/
+EDDSA.prototype.encodePoint = function encodePoint(point) {
+ var enc = point.getY().toArray('le', this.encodingLength);
+ enc[this.encodingLength - 1] |= point.getX().isOdd() ? 0x80 : 0;
+ return enc;
+};
+
+EDDSA.prototype.decodePoint = function decodePoint(bytes) {
+ bytes = utils.parseBytes(bytes);
+
+ var lastIx = bytes.length - 1;
+ var normed = bytes.slice(0, lastIx).concat(bytes[lastIx] & ~0x80);
+ var xIsOdd = (bytes[lastIx] & 0x80) !== 0;
+
+ var y = utils.intFromLE(normed);
+ return this.curve.pointFromY(y, xIsOdd);
+};
+
+EDDSA.prototype.encodeInt = function encodeInt(num) {
+ return num.toArray('le', this.encodingLength);
+};
+
+EDDSA.prototype.decodeInt = function decodeInt(bytes) {
+ return utils.intFromLE(bytes);
+};
+
+EDDSA.prototype.isPoint = function isPoint(val) {
+ return val instanceof this.pointClass;
+};
+
+},{"../../../../../base/functions/encode":10,"../../../../BN/bn.js":123,"../../../../crypto-js/crypto-js":124,"../curves":131,"../utils":139,"./key":136,"./signature":137}],136:[function(require,module,exports){
+'use strict';
+
+var utils = require('../utils');
+var assert = utils.assert;
+var parseBytes = utils.parseBytes;
+var cachedProperty = utils.cachedProperty;
+
+/**
+* @param {EDDSA} eddsa - instance
+* @param {Object} params - public/private key parameters
+*
+* @param {Array} [params.secret] - secret seed bytes
+* @param {Point} [params.pub] - public key point (aka `A` in eddsa terms)
+* @param {Array} [params.pub] - public key point encoded as bytes
+*
+*/
+function KeyPair(eddsa, params) {
+ this.eddsa = eddsa;
+ this._secret = parseBytes(params.secret);
+ if (eddsa.isPoint(params.pub))
+ this._pub = params.pub;
+ else
+ this._pubBytes = parseBytes(params.pub);
+}
+
+KeyPair.fromPublic = function fromPublic(eddsa, pub) {
+ if (pub instanceof KeyPair)
+ return pub;
+ return new KeyPair(eddsa, { pub: pub });
+};
+
+KeyPair.fromSecret = function fromSecret(eddsa, secret) {
+ if (secret instanceof KeyPair)
+ return secret;
+ return new KeyPair(eddsa, { secret: secret });
+};
+
+KeyPair.prototype.secret = function secret() {
+ return this._secret;
+};
+
+cachedProperty(KeyPair, 'pubBytes', function pubBytes() {
+ return this.eddsa.encodePoint(this.pub());
+});
+
+cachedProperty(KeyPair, 'pub', function pub() {
+ if (this._pubBytes)
+ return this.eddsa.decodePoint(this._pubBytes);
+ return this.eddsa.g.mul(this.priv());
+});
+
+cachedProperty(KeyPair, 'privBytes', function privBytes() {
+ var eddsa = this.eddsa;
+ var hash = this.hash();
+ var lastIx = eddsa.encodingLength - 1;
+
+ var a = hash.slice(0, eddsa.encodingLength);
+ a[0] &= 248;
+ a[lastIx] &= 127;
+ a[lastIx] |= 64;
+
+ return a;
+});
+
+cachedProperty(KeyPair, 'priv', function priv() {
+ return this.eddsa.decodeInt(this.privBytes());
+});
+
+cachedProperty(KeyPair, 'hash', function hash() {
+ return this.eddsa.hash().update(this.secret()).digest();
+});
+
+cachedProperty(KeyPair, 'messagePrefix', function messagePrefix() {
+ return this.hash().slice(this.eddsa.encodingLength);
+});
+
+KeyPair.prototype.sign = function sign(message) {
+ assert(this._secret, 'KeyPair can only verify');
+ return this.eddsa.sign(message, this);
+};
+
+KeyPair.prototype.signModified = function sign(message) {
+ assert(this._secret, 'KeyPair can only verify');
+ return this.eddsa.signModified(message, this);
+};
+
+KeyPair.prototype.verify = function verify(message, sig) {
+ return this.eddsa.verify(message, sig, this);
+};
+
+KeyPair.prototype.getSecret = function getSecret(enc) {
+ assert(this._secret, 'KeyPair is public only');
+ return utils.encode(this.secret(), enc);
+};
+
+KeyPair.prototype.getPublic = function getPublic(enc) {
+ return utils.encode(this.pubBytes(), enc);
+};
+
+module.exports = KeyPair;
+
+},{"../utils":139}],137:[function(require,module,exports){
+'use strict';
+
+var BN = require('../../../../BN/bn');
+var utils = require('../utils');
+var assert = utils.assert;
+var cachedProperty = utils.cachedProperty;
+var parseBytes = utils.parseBytes;
+
+/**
+* @param {EDDSA} eddsa - eddsa instance
+* @param {Array|Object} sig -
+* @param {Array|Point} [sig.R] - R point as Point or bytes
+* @param {Array|bn} [sig.S] - S scalar as bn or bytes
+* @param {Array} [sig.Rencoded] - R point encoded
+* @param {Array} [sig.Sencoded] - S scalar encoded
+*/
+function Signature(eddsa, sig) {
+ this.eddsa = eddsa;
+
+ if (typeof sig !== 'object')
+ sig = parseBytes(sig);
+
+ if (Array.isArray(sig)) {
+ sig = {
+ R: sig.slice(0, eddsa.encodingLength),
+ S: sig.slice(eddsa.encodingLength)
+ };
+ }
+
+ assert(sig.R && sig.S, 'Signature without R or S');
+
+ if (eddsa.isPoint(sig.R))
+ this._R = sig.R;
+ if (sig.S instanceof BN)
+ this._S = sig.S;
+
+ this._Rencoded = Array.isArray(sig.R) ? sig.R : sig.Rencoded;
+ this._Sencoded = Array.isArray(sig.S) ? sig.S : sig.Sencoded;
+}
+
+cachedProperty(Signature, 'S', function S() {
+ return this.eddsa.decodeInt(this.Sencoded());
+});
+
+cachedProperty(Signature, 'R', function R() {
+ return this.eddsa.decodePoint(this.Rencoded());
+});
+
+cachedProperty(Signature, 'Rencoded', function Rencoded() {
+ return this.eddsa.encodePoint(this.R());
+});
+
+cachedProperty(Signature, 'Sencoded', function Sencoded() {
+ return this.eddsa.encodeInt(this.S());
+});
+
+Signature.prototype.toBytes = function toBytes() {
+ return this.Rencoded().concat(this.Sencoded());
+};
+
+Signature.prototype.toHex = function toHex() {
+ return utils.encode(this.toBytes(), 'hex').toUpperCase();
+};
+
+module.exports = Signature;
+
+},{"../../../../BN/bn":123,"../utils":139}],138:[function(require,module,exports){
module.exports = {
doubles: {
step: 4,
@@ -96230,7 +116529,7 @@ module.exports = {
}
};
-},{}],132:[function(require,module,exports){
+},{}],139:[function(require,module,exports){
'use strict';
var utils = exports;
@@ -96388,7 +116687,65 @@ function wordArrayToBuffer(wordArray) {
utils.wordArrayToBuffer = wordArrayToBuffer;
-},{"../../../BN/bn":119}],133:[function(require,module,exports){
+// https://github.com/indutny/minimalistic-crypto-utils/blob/master/lib/utils.js
+// moved here to remove the dep
+
+function toArray(msg, enc) {
+ if (Array.isArray(msg))
+ return msg.slice();
+ if (!msg)
+ return [];
+ var res = [];
+ if (typeof msg !== 'string') {
+ for (var i = 0; i < msg.length; i++)
+ res[i] = msg[i] | 0;
+ return res;
+ }
+ if (enc === 'hex') {
+ msg = msg.replace(/[^a-z0-9]+/ig, '');
+ if (msg.length % 2 !== 0)
+ msg = '0' + msg;
+ for (var i = 0; i < msg.length; i += 2)
+ res.push(parseInt(msg[i] + msg[i + 1], 16));
+ } else {
+ for (var i = 0; i < msg.length; i++) {
+ var c = msg.charCodeAt(i);
+ var hi = c >> 8;
+ var lo = c & 0xff;
+ if (hi)
+ res.push(hi, lo);
+ else
+ res.push(lo);
+ }
+ }
+ return res;
+}
+utils.toArray = toArray;
+
+function zero2(word) {
+ if (word.length === 1)
+ return '0' + word;
+ else
+ return word;
+}
+utils.zero2 = zero2;
+
+function toHex(msg) {
+ var res = '';
+ for (var i = 0; i < msg.length; i++)
+ res += zero2(msg[i].toString(16));
+ return res;
+}
+utils.toHex = toHex;
+
+utils.encode = function encode(arr, enc) {
+ if (enc === 'hex')
+ return toHex(arr);
+ else
+ return arr;
+};
+
+},{"../../../BN/bn":123}],140:[function(require,module,exports){
'use strict';
var CryptoJS = require('../../../crypto-js/crypto-js');
@@ -96504,7 +116861,7 @@ HmacDRBG.prototype.generate = function generate(len, enc, add, addEnc) {
return utils.wordArrayToBuffer(res);
};
-},{"../../../../base/functions/encode":12,"../../../crypto-js/crypto-js":120,"../elliptic/utils":132}],134:[function(require,module,exports){
+},{"../../../../base/functions/encode":10,"../../../crypto-js/crypto-js":124,"../elliptic/utils":139}],141:[function(require,module,exports){
'use strict';
var fetch = require('../node-fetch/index');
@@ -96545,7 +116902,7 @@ module.exports = function (context) {
};
};
-},{"../node-fetch/index":135}],135:[function(require,module,exports){
+},{"../node-fetch/index":142}],142:[function(require,module,exports){
(function (global,Buffer){
'use strict';
@@ -98113,7 +118470,7 @@ exports.Response = Response;
exports.FetchError = FetchError;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
-},{"buffer":178,"http":220,"https":183,"stream":219,"url":226,"zlib":177}],136:[function(require,module,exports){
+},{"buffer":185,"http":227,"https":190,"stream":226,"url":233,"zlib":184}],143:[function(require,module,exports){
(function (Buffer){
/*!
* RSA library for Node.js
@@ -98340,7 +118697,7 @@ module.exports = (function () {
})();
}).call(this,require("buffer").Buffer)
-},{"./formats/formats.js":143,"./libs/rsa.js":147,"./schemes/schemes.js":149,"./utils":150,"buffer":178}],137:[function(require,module,exports){
+},{"./formats/formats.js":150,"./libs/rsa.js":154,"./schemes/schemes.js":156,"./utils":157,"buffer":185}],144:[function(require,module,exports){
// Copyright 2011 Mark Cavage All rights reserved.
@@ -98355,7 +118712,7 @@ module.exports = {
};
-},{}],138:[function(require,module,exports){
+},{}],145:[function(require,module,exports){
// Copyright 2011 Mark Cavage All rights reserved.
var errors = require('./errors');
@@ -98378,7 +118735,7 @@ for (var e in errors) {
module.exports[e] = errors[e];
}
-},{"./errors":137,"./reader":139,"./types":140}],139:[function(require,module,exports){
+},{"./errors":144,"./reader":146,"./types":147}],146:[function(require,module,exports){
(function (Buffer){
// Copyright 2011 Mark Cavage All rights reserved.
@@ -98644,7 +119001,7 @@ Reader.prototype._readTag = function (tag) {
module.exports = Reader;
}).call(this,require("buffer").Buffer)
-},{"./errors":137,"./types":140,"assert":173,"buffer":178}],140:[function(require,module,exports){
+},{"./errors":144,"./types":147,"assert":180,"buffer":185}],147:[function(require,module,exports){
// Copyright 2011 Mark Cavage All rights reserved.
@@ -98682,7 +119039,7 @@ module.exports = {
Context: 128
};
-},{}],141:[function(require,module,exports){
+},{}],148:[function(require,module,exports){
// Copyright 2011 Mark Cavage All rights reserved.
// If you have no idea what ASN.1 or BER is, see this:
@@ -98701,7 +119058,7 @@ module.exports = {
BerReader: Ber.Reader,
};
-},{"./ber/index":138}],142:[function(require,module,exports){
+},{"./ber/index":145}],149:[function(require,module,exports){
var _ = require('../utils')._;
var utils = require('../utils');
@@ -98774,7 +119131,7 @@ module.exports = {
}
};
-},{"../utils":150}],143:[function(require,module,exports){
+},{"../utils":157}],150:[function(require,module,exports){
var _ = require('../utils')._;
module.exports = {
@@ -98807,7 +119164,7 @@ module.exports = {
},
};
-},{"../utils":150,"./components":142,"./pkcs1":144,"./pkcs8":145}],144:[function(require,module,exports){
+},{"../utils":157,"./components":149,"./pkcs1":151,"./pkcs8":152}],151:[function(require,module,exports){
(function (Buffer){
var ber = require('../asn1/index').Ber;
var _ = require('../utils')._;
@@ -98959,7 +119316,7 @@ module.exports = {
};
}).call(this,require("buffer").Buffer)
-},{"../asn1/index":141,"../utils":150,"buffer":178}],145:[function(require,module,exports){
+},{"../asn1/index":148,"../utils":157,"buffer":185}],152:[function(require,module,exports){
(function (Buffer){
var ber = require('../asn1/index').Ber;
var _ = require('../utils')._;
@@ -99150,7 +119507,7 @@ module.exports = {
};
}).call(this,require("buffer").Buffer)
-},{"../asn1/index":141,"../utils":150,"buffer":178}],146:[function(require,module,exports){
+},{"../asn1/index":148,"../utils":157,"buffer":185}],153:[function(require,module,exports){
(function (Buffer){
/*
* Basic JavaScript BN library - subset useful for RSA encryption.
@@ -100406,7 +120763,7 @@ BigInteger.prototype.square = bnSquare;
module.exports = BigInteger;
}).call(this,require("buffer").Buffer)
-},{"../utils":150,"buffer":178}],147:[function(require,module,exports){
+},{"../utils":157,"buffer":185}],154:[function(require,module,exports){
/*
* RSA Encryption / Decryption with PKCS1 v2 Padding.
*
@@ -100555,7 +120912,7 @@ module.exports.Key = (function () {
})();
-},{"../schemes/schemes.js":149,"../utils":150,"../utils.js":150,"./jsbn.js":146}],148:[function(require,module,exports){
+},{"../schemes/schemes.js":156,"../utils":157,"../utils.js":157,"./jsbn.js":153}],155:[function(require,module,exports){
(function (Buffer){
/**
* PKCS1 padding and signature scheme
@@ -100735,7 +121092,7 @@ function wordArrayToBuffer(wordArray) {
}
}).call(this,require("buffer").Buffer)
-},{"../../crypto-js/crypto-js":120,"../libs/jsbn":146,"buffer":178,"constants":180}],149:[function(require,module,exports){
+},{"../../crypto-js/crypto-js":124,"../libs/jsbn":153,"buffer":185,"constants":187}],156:[function(require,module,exports){
module.exports = {
pkcs1: require('./pkcs1'),
@@ -100758,7 +121115,7 @@ module.exports = {
}
};
-},{"./pkcs1":148}],150:[function(require,module,exports){
+},{"./pkcs1":155}],157:[function(require,module,exports){
/*
* Utils functions
*
@@ -100858,7 +121215,7 @@ module.exports.trimSurroundingText = function (data, opening, closing) {
return data.substring(trimStartIndex, trimEndIndex);
}
-},{}],151:[function(require,module,exports){
+},{}],158:[function(require,module,exports){
'use strict';
var replace = String.prototype.replace;
@@ -100878,7 +121235,7 @@ module.exports = {
RFC3986: 'RFC3986'
};
-},{}],152:[function(require,module,exports){
+},{}],159:[function(require,module,exports){
'use strict';
var stringify = require('./stringify');
@@ -100891,7 +121248,7 @@ module.exports = {
stringify: stringify
};
-},{"./formats":151,"./parse":153,"./stringify":154}],153:[function(require,module,exports){
+},{"./formats":158,"./parse":160,"./stringify":161}],160:[function(require,module,exports){
'use strict';
var utils = require('./utils');
@@ -101135,7 +121492,7 @@ module.exports = function (str, opts) {
return utils.compact(obj);
};
-},{"./utils":155}],154:[function(require,module,exports){
+},{"./utils":162}],161:[function(require,module,exports){
'use strict';
var utils = require('./utils');
@@ -101406,7 +121763,7 @@ module.exports = function (object, opts) {
return joined.length > 0 ? prefix + joined : '';
};
-},{"./formats":151,"./utils":155}],155:[function(require,module,exports){
+},{"./formats":158,"./utils":162}],162:[function(require,module,exports){
'use strict';
var has = Object.prototype.hasOwnProperty;
@@ -101638,7 +121995,7 @@ module.exports = {
merge: merge
};
-},{}],156:[function(require,module,exports){
+},{}],163:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -101658,25 +122015,30 @@ module.exports = class stex extends Exchange {
'certified': false,
// new metainfo interface
'has': {
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': false,
+ 'createDepositAddress': true,
'createMarketOrder': false, // limit orders only
- 'fetchCurrencies': true,
- 'fetchMarkets': true,
- 'fetchTicker': true,
- 'fetchTickers': true,
- 'fetchOrderBook': true,
- 'fetchOHLCV': true,
+ 'createOrder': true,
'fetchBalance': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchFundingFees': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
- 'fetchMyTrades': true,
+ 'fetchOrderBook': true,
'fetchOrderTrades': true,
- 'fetchDepositAddress': true,
- 'createDepositAddress': true,
- 'fetchDeposits': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchWithdrawals': true,
'withdraw': true,
- 'fetchFundingFees': true,
},
'version': 'v3',
'urls': {
@@ -101817,6 +122179,9 @@ module.exports = class stex extends Exchange {
},
},
'commonCurrencies': {
+ 'BC': 'Bitcoin Confidential',
+ 'BITS': 'Bitcoinus',
+ 'BITSW': 'BITS',
'BHD': 'Bithold',
},
'options': {
@@ -102052,6 +122417,26 @@ module.exports = class stex extends Exchange {
return this.parseTicker (ticker, market);
}
+ async fetchTime (params = {}) {
+ 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 = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -102127,22 +122512,8 @@ module.exports = class stex extends Exchange {
// }
//
const timestamp = this.safeInteger (ticker, 'timestamp');
- let symbol = undefined;
- let marketId = this.safeString (ticker, 'id');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- marketId = this.safeString (ticker, 'symbol');
- if (marketId !== undefined) {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString2 (ticker, 'id', 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
const last = this.safeFloat (ticker, 'last');
const open = this.safeFloat (ticker, 'open');
let change = undefined;
@@ -102237,7 +122608,7 @@ module.exports = class stex extends Exchange {
return this.parseTickers (tickers, symbols);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// "time": 1566086400000,
@@ -102299,8 +122670,8 @@ module.exports = class stex extends Exchange {
// ]
// }
//
- const ohlcvs = this.safeValue (response, 'data', []);
- return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
parseTrade (trade, market = undefined) {
@@ -102507,22 +122878,8 @@ module.exports = class stex extends Exchange {
//
const id = this.safeString (order, 'id');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let symbol = undefined;
- let marketId = this.safeString (order, 'currency_pair_id');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- marketId = this.safeString (order, 'currency_pair_name');
- if (marketId !== undefined) {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString2 (order, 'currency_pair_id', 'currency_pair_name');
+ const symbol = this.safeSymbol (marketId, market, '_');
const timestamp = this.safeTimestamp (order, 'timestamp');
const price = this.safeFloat (order, 'price');
const amount = this.safeFloat (order, 'initial_amount');
@@ -102556,6 +122913,7 @@ module.exports = class stex extends Exchange {
'order': id,
});
}
+ const stopPrice = this.safeFloat (order, 'trigger_price');
const result = {
'info': order,
'id': id,
@@ -102565,8 +122923,10 @@ module.exports = class stex extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': undefined,
@@ -103439,800 +123799,7 @@ module.exports = class stex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],157:[function(require,module,exports){
-'use strict';
-
-// ----------------------------------------------------------------------------
-
-const Exchange = require ('./base/Exchange');
-const { InvalidNonce, AuthenticationError, AccountSuspended, InsufficientFunds, ExchangeError, ArgumentsRequired, NotSupported } = require ('./base/errors');
-
-// ----------------------------------------------------------------------------
-
-module.exports = class stronghold extends Exchange {
- describe () {
- return this.deepExtend (super.describe (), {
- 'id': 'stronghold',
- 'name': 'Stronghold',
- 'country': [ 'US' ],
- 'rateLimit': 1000,
- 'version': 'v1',
- 'comment': 'This comment is optional',
- 'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/52160042-98c1f300-26be-11e9-90dd-da8473944c83.jpg',
- 'api': {
- 'public': 'https://api.stronghold.co',
- 'private': 'https://api.stronghold.co',
- },
- 'www': 'https://stronghold.co',
- 'doc': [
- 'https://docs.stronghold.co',
- ],
- },
- 'requiredCredentials': {
- 'apiKey': true,
- 'secret': true,
- 'password': true,
- },
- 'has': {
- 'fetchMarkets': true,
- 'fetchCurrencies': true,
- 'fetchOrderBook': true,
- 'fetchOpenOrders': true,
- 'fetchTime': true,
- 'fetchTrades': true,
- 'fetchMyTrades': true,
- 'fetchDepositAddress': false,
- 'createDepositAddress': true,
- 'withdraw': true,
- 'fetchTicker': false,
- 'fetchTickers': false,
- 'fetchAccounts': true,
- 'fetchTransactions': true,
- },
- 'api': {
- 'public': {
- 'get': [
- 'utilities/time',
- 'utilities/uuid',
- 'venues',
- 'venues/{venueId}/assets',
- 'venues/{venueId}/markets',
- 'venues/{venueId}/markets/{marketId}/orderbook',
- 'venues/{venueId}/markets/{marketId}/trades',
- ],
- 'post': [
- 'venues/{venueId}/assets',
- 'iam/credentials',
- 'identities',
- ],
- 'patch': [
- 'identities',
- ],
- 'put': [
- 'iam/credentials/{credentialId}',
- ],
- 'delete': [
- 'iam/credentials/{credentialId}',
- ],
- },
- 'private': {
- 'get': [
- 'venues',
- 'venues/{venueId}/accounts',
- 'venues/{venueId}/accounts/{accountId}',
- 'venues/{venueId}/accounts/{accountId}/payments/{paymentId}',
- 'venues/{venueId}/accounts/{accountId}/orders',
- 'venues/{venueId}/accounts/{accountId}/trades',
- 'venues/{venueId}/accounts/{accountId}/transactions',
- ],
- 'post': [
- 'venues/{venueId}/accounts',
- 'venues/{venueId}/accounts/{accountId}/orders',
- 'venues/{venueId}/accounts/{accountId}/deposit',
- 'venues/{venueId}/accounts/{accountId}/withdrawal',
- 'venues/{venueId}/accounts/{accountId}/payments',
- 'venues/{venueId}/accounts/{accountId}/payments/{paymentId}/stop',
- 'venues/{venueId}/custody/accounts/{accountId}/operations/{operationId}/signatures',
- 'venues/{venueId}/anchor/withdrawal',
- 'venues/{venueId}/testing/friendbot',
- ],
- 'delete': [
- 'venues/{venueId}/accounts/{accountId}/orders/{orderId}',
- ],
- },
- },
- 'options': {
- 'accountId': undefined,
- 'venueId': 'trade-public',
- 'venues': {
- 'trade': 'trade-public',
- 'sandbox': 'sandbox-public',
- },
- 'paymentMethods': {
- 'ETH': 'ethereum',
- 'BTC': 'bitcoin',
- 'XLM': 'stellar',
- 'XRP': 'ripple',
- 'LTC': 'litecoin',
- 'SHX': 'stellar',
- },
- },
- 'exceptions': {
- 'CREDENTIAL_MISSING': AuthenticationError,
- 'CREDENTIAL_INVALID': AuthenticationError,
- 'CREDENTIAL_REVOKED': AccountSuspended,
- 'CREDENTIAL_NO_IDENTITY': AuthenticationError,
- 'PASSPHRASE_INVALID': AuthenticationError,
- 'SIGNATURE_INVALID': AuthenticationError,
- 'TIME_INVALID': InvalidNonce,
- 'BYPASS_INVALID': AuthenticationError,
- 'INSUFFICIENT_FUNDS': InsufficientFunds,
- },
- });
- }
-
- async getActiveAccount () {
- if (this.options['accountId'] !== undefined) {
- return this.options['accountId'];
- }
- await this.loadAccounts ();
- const numAccounts = this.accounts.length;
- if (numAccounts > 0) {
- return this.accounts[0]['id'];
- }
- throw new ExchangeError (this.id + ' requires an accountId.');
- }
-
- async fetchAccounts (params = {}) {
- const request = {
- 'venueId': this.options['venueId'],
- };
- const response = await this.privateGetVenuesVenueIdAccounts (this.extend (request, params));
- //
- // [ { id: '34080200-b25a-483d-a734-255d30ba324d',
- // venueSpecificId: '' } ... ]
- //
- return response['result'];
- }
-
- async fetchTime (params = {}) {
- const response = await this.publicGetUtilitiesTime (params);
- //
- // {
- // "requestId": "6de8f506-ad9d-4d0d-94f3-ec4d55dfcdb9",
- // "timestamp": 1536436649207281,
- // "success": true,
- // "statusCode": 200,
- // "result": {
- // "timestamp": "2018-09-08T19:57:29.207282Z"
- // }
- // }
- //
- return this.parse8601 (this.safeString (response['result'], 'timestamp'));
- }
-
- async fetchMarkets (params = {}) {
- const request = {
- 'venueId': this.options['venueId'],
- };
- const response = await this.publicGetVenuesVenueIdMarkets (this.extend (request, params));
- const data = response['result'];
- //
- // [
- // {
- // id: 'SHXUSD',
- // baseAssetId: 'SHX/stronghold.co',
- // counterAssetId: 'USD/stronghold.co',
- // minimumOrderSize: '1.0000000',
- // minimumOrderIncrement: '1.0000000',
- // minimumPriceIncrement: '0.00010000',
- // displayDecimalsPrice: 4,
- // displayDecimalsAmount: 0
- // },
- // ...
- // ]
- //
- const result = {};
- for (let i = 0; i < data.length; i++) {
- const entry = data[i];
- const marketId = entry['id'];
- const baseId = this.safeString (entry, 'baseAssetId');
- const quoteId = this.safeString (entry, 'counterAssetId');
- const baseAssetId = baseId.split ('/')[0];
- const quoteAssetId = quoteId.split ('/')[0];
- const base = this.safeCurrencyCode (baseAssetId);
- const quote = this.safeCurrencyCode (quoteAssetId);
- const symbol = base + '/' + quote;
- const limits = {
- 'amount': {
- 'min': this.safeFloat (entry, 'minimumOrderSize'),
- 'max': undefined,
- },
- };
- const precision = {
- 'price': this.safeInteger (entry, 'displayDecimalsPrice'),
- 'amount': this.safeInteger (entry, 'displayDecimalsAmount'),
- };
- result[symbol] = {
- 'symbol': symbol,
- 'id': marketId,
- 'base': base,
- 'quote': quote,
- 'baseId': baseId,
- 'quoteId': quoteId,
- 'precision': precision,
- 'info': entry,
- 'limits': limits,
- 'active': undefined,
- };
- }
- return result;
- }
-
- async fetchCurrencies (params = {}) {
- const request = {
- 'venueId': this.options['venueId'],
- };
- const response = await this.publicGetVenuesVenueIdAssets (this.extend (request, params));
- //
- // [
- // {
- // id: 'XLM/native',
- // alias: '',
- // code: 'XLM',
- // name: '',
- // displayDecimalsFull: 7,
- // displayDecimalsSignificant: 2,
- // },
- // ...
- // ]
- //
- const data = response['result'];
- const result = {};
- const limits = {
- 'amount': {
- 'min': undefined,
- 'max': undefined,
- },
- 'price': {
- 'min': undefined,
- 'max': undefined,
- },
- 'cost': {
- 'min': undefined,
- 'max': undefined,
- },
- 'withdraw': {
- 'min': undefined,
- 'max': undefined,
- },
- };
- for (let i = 0; i < data.length; i++) {
- const entry = data[i];
- const assetId = this.safeString (entry, 'id');
- const currencyId = this.safeString (entry, 'code');
- const code = this.safeCurrencyCode (currencyId);
- const precision = this.safeInteger (entry, 'displayDecimalsFull');
- result[code] = {
- 'code': code,
- 'id': assetId,
- 'precision': precision,
- 'info': entry,
- 'active': undefined,
- 'name': undefined,
- 'limits': limits,
- 'fee': undefined,
- };
- }
- return result;
- }
-
- async fetchOrderBook (symbol, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const marketId = this.marketId (symbol);
- const request = {
- 'marketId': marketId,
- 'venueId': this.options['venueId'],
- };
- const response = await this.publicGetVenuesVenueIdMarketsMarketIdOrderbook (this.extend (request, params));
- //
- // {
- // marketId: 'ETHBTC',
- // bids: [
- // [ '0.031500', '7.385000' ],
- // ...,
- // ],
- // asks: [
- // [ '0.031500', '7.385000' ],
- // ...,
- // ],
- // }
- //
- const data = response['result'];
- const timestamp = this.parse8601 (this.safeString (response, 'timestamp'));
- return this.parseOrderBook (data, timestamp);
- }
-
- async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'marketId': market['id'],
- 'venueId': this.options['venueId'],
- };
- const response = await this.publicGetVenuesVenueIdMarketsMarketIdTrades (this.extend (request, params));
- //
- // {
- // "requestId": "4d343700-b53f-4975-afcc-732ae9d3c828",
- // "timestamp": "2018-11-08T19:22:11.399543Z",
- // "success": true,
- // "statusCode": 200,
- // "result": {
- // "marketId": "",
- // "trades": [
- // [ "0.9", "3.10", "sell", "2018-11-08T19:22:11.399547Z" ],
- // ...
- // ],
- // }
- // }
- //
- return this.parseTrades (response['result']['trades'], market, since, limit);
- }
-
- parseTrade (trade, market = undefined) {
- //
- // fetchTrades (public)
- //
- // [ '0.03177000', '0.0643501', 'sell', '2019-01-27T23:02:04Z' ]
- //
- // fetchMyTrades (private)
- //
- // {
- // id: '9cdb109c-d035-47e2-81f8-a0c802c9c5f9',
- // orderId: 'a38d8bcb-9ff5-4c52-81a0-a40196a66462',
- // marketId: 'XLMUSD',
- // side: 'sell',
- // size: '1.0000000',
- // price: '0.10440600',
- // settled: true,
- // maker: false,
- // executedAt: '2019-02-01T18:44:21Z'
- // }
- //
- let id = undefined;
- let takerOrMaker = undefined;
- let price = undefined;
- let amount = undefined;
- let cost = undefined;
- let side = undefined;
- let timestamp = undefined;
- let orderId = undefined;
- if (Array.isArray (trade)) {
- price = parseFloat (trade[0]);
- amount = parseFloat (trade[1]);
- side = trade[2];
- timestamp = this.parse8601 (trade[3]);
- } else {
- id = this.safeString (trade, 'id');
- price = this.safeFloat (trade, 'price');
- amount = this.safeFloat (trade, 'size');
- side = this.safeString (trade, 'side');
- timestamp = this.parse8601 (this.safeString (trade, 'executedAt'));
- orderId = this.safeString (trade, 'orderId');
- const marketId = this.safeString (trade, 'marketId');
- market = this.safeValue (this.markets_by_id, marketId);
- const isMaker = this.safeValue (trade, 'maker');
- takerOrMaker = isMaker ? 'maker' : 'taker';
- }
- if (amount !== undefined && price !== undefined) {
- cost = amount * price;
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- return {
- 'id': id,
- 'info': trade,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'symbol': symbol,
- 'type': undefined,
- 'order': orderId,
- 'side': side,
- 'price': price,
- 'amount': amount,
- 'cost': cost,
- 'takerOrMaker': takerOrMaker,
- 'fee': {
- 'cost': undefined,
- 'currency': undefined,
- 'rate': undefined,
- },
- };
- }
-
- async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const request = this.extend ({
- 'venueId': this.options['venueId'],
- 'accountId': await this.getActiveAccount (),
- }, params);
- if (!request['accountId']) {
- throw new ArgumentsRequired (this.id + " fetchTransactions requires either the 'accountId' extra parameter or exchange.options['accountId'] = 'YOUR_ACCOUNT_ID'.");
- }
- const response = await this.privateGetVenuesVenueIdAccountsAccountIdTransactions (request);
- let currency = undefined;
- if (code !== undefined) {
- currency = this.currency (code);
- }
- return this.parseTransactions (response['result'], currency, since, limit);
- }
-
- parseTransactionStatus (status) {
- const statuses = {
- 'queued': 'pending',
- 'settling': 'pending',
- };
- return this.safeString (statuses, status, status);
- }
-
- parseTransaction (transaction, currency = undefined) {
- // {
- // "id": "6408e003-0f14-4457-9340-ba608992ad5c",
- // "status": "queued",
- // "direction": "outgoing",
- // "amount": "98.95000000",
- // "assetId": "XLM/native",
- // "sourceAccount": {
- // "id": "774fa8ef-600b-4636-b9ed-cd6d23421915",
- // "venueSpecificId": "GC5FIBIQZTQRMJE34GYF5EKH77GEQ3OHFX3NIP5OKDIZFA6VERLZSHY6"
- // },
- // "destinationAccount": {
- // "id": "f72b9fb5-9607-4dd3-b31f-6ded21337056",
- // "venueSpecificId": "GAOWV6CYBE7DEWSWPODXLMI5YB75VXXZJX5OYVQ2YLZH2TVA3TMMSNYW"
- // }
- // }
- const id = this.safeString (transaction, 'id');
- const assetId = this.safeString (transaction, 'assetId');
- let code = undefined;
- if (assetId !== undefined) {
- const currencyId = assetId.split ('/')[0];
- code = this.safeCurrencyCode (currencyId);
- } else {
- if (currency !== undefined) {
- code = currency['code'];
- }
- }
- const amount = this.safeFloat (transaction, 'amount');
- const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
- const feeCost = this.safeFloat (transaction, 'feeAmount');
- let feeRate = undefined;
- if (feeCost !== undefined) {
- feeRate = feeCost / amount;
- }
- const direction = this.safeString (transaction, 'direction');
- const datetime = this.safeString (transaction, 'requestedAt');
- const timestamp = this.parse8601 (datetime);
- const updated = this.parse8601 (this.safeString (transaction, 'updatedAt'));
- const type = (direction === 'outgoing' || direction === 'withdrawal') ? 'withdrawal' : 'deposit';
- const fee = {
- 'cost': feeCost,
- 'rate': feeRate,
- };
- return {
- 'id': id,
- 'info': transaction,
- 'currency': code,
- 'amount': amount,
- 'status': status,
- 'fee': fee,
- 'tag': undefined,
- 'type': type,
- 'updated': updated,
- 'address': undefined,
- 'txid': undefined,
- 'timestamp': timestamp,
- 'datetime': datetime,
- };
- }
-
- async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = this.extend ({
- 'venueId': this.options['venueId'],
- 'accountId': await this.getActiveAccount (),
- 'marketID': market['id'],
- 'type': type,
- 'side': side,
- 'size': this.amountToPrecision (symbol, amount),
- 'price': this.priceToPrecision (symbol, price),
- }, params);
- if (!request['accountId']) {
- throw new ArgumentsRequired (this.id + " createOrder requires either the 'accountId' extra parameter or exchange.options['accountId'] = 'YOUR_ACCOUNT_ID'.");
- }
- const response = await this.privatePostVenuesVenueIdAccountsAccountIdOrders (request);
- return this.parseOrder (response, market);
- }
-
- async cancelOrder (id, symbol = undefined, params = {}) {
- const request = this.extend ({
- 'venueId': this.options['venueId'],
- 'accountId': await this.getActiveAccount (),
- 'orderId': id,
- }, params);
- if (!request['accountId']) {
- throw new ArgumentsRequired (this.id + " cancelOrder requires either the 'accountId' extra parameter or exchange.options['accountId'] = 'YOUR_ACCOUNT_ID'.");
- }
- const response = await this.privateDeleteVenuesVenueIdAccountsAccountIdOrdersOrderId (request);
- return this.parseOrder (response);
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- }
- const request = this.extend ({
- 'venueId': this.options['venueId'],
- 'accountId': await this.getActiveAccount (),
- }, params);
- if (!request['accountId']) {
- throw new ArgumentsRequired (this.id + " cancelOrder requires either the 'accountId' extra parameter or exchange.options['accountId'] = 'YOUR_ACCOUNT_ID'.");
- }
- const response = await this.privateGetVenuesVenueIdAccountsAccountIdOrders (request);
- return this.parseOrders (response['result'], market, since, limit);
- }
-
- parseOrder (order, market = undefined) {
- // { id: '178596',
- // marketId: 'XLMUSD',
- // side: 'buy',
- // size: '1.0000000',
- // sizeFilled: '0',
- // price: '0.10000000',
- // placedAt: '2019-02-01T19:47:52Z' }
- const marketId = this.safeString (order, 'marketId');
- if (marketId !== undefined) {
- market = this.safeValue (this.marketsById, marketId);
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- const id = this.safeString (order, 'id');
- const datetime = this.safeString (order, 'placedAt');
- const amount = this.safeFloat (order, 'size');
- const price = this.safeFloat (order, 'price');
- const filled = this.safeFloat (order, 'sizeFilled');
- let cost = undefined;
- let remaining = undefined;
- if (amount !== undefined) {
- if (filled !== undefined) {
- remaining = amount - filled;
- }
- if (price !== undefined) {
- cost = amount * price;
- }
- }
- return {
- 'id': id,
- 'clientOrderId': undefined,
- 'info': order,
- 'symbol': symbol,
- 'datetime': datetime,
- 'timestamp': this.parse8601 (datetime),
- 'side': this.safeString (order, 'side'),
- 'amount': amount,
- 'filled': filled,
- 'remaining': remaining,
- 'price': price,
- 'cost': cost,
- 'trades': [],
- 'lastTradeTimestamp': undefined,
- 'status': undefined,
- 'type': undefined,
- 'average': undefined,
- 'fee': undefined,
- };
- }
-
- nonce () {
- return this.seconds ();
- }
-
- setSandboxMode (enabled) {
- if (enabled) {
- this.options['venueId'] = this.options['venues']['sandbox'];
- } else {
- this.options['venueId'] = this.options['venues']['trade'];
- }
- }
-
- async fetchBalance (params = {}) {
- const request = this.extend ({
- 'venueId': this.options['venueId'],
- 'accountId': await this.getActiveAccount (),
- }, params);
- if (!('accountId' in request)) {
- throw new ArgumentsRequired (this.id + " fetchBalance requires either the 'accountId' extra parameter or exchange.options['accountId'] = 'YOUR_ACCOUNT_ID'.");
- }
- const response = await this.privateGetVenuesVenueIdAccountsAccountId (request);
- const balances = this.safeValue (response['result'], 'balances');
- const result = { 'info': response };
- for (let i = 0; i < balances.length; i++) {
- const balance = balances[i];
- const assetId = this.safeString (balance, 'assetId');
- if (assetId !== undefined) {
- const currencyId = assetId.split ('/')[0];
- const code = this.safeCurrencyCode (currencyId);
- const account = {};
- account['total'] = this.safeFloat (balance, 'amount');
- account['free'] = this.safeFloat (balance, 'availableForTrade');
- result[code] = account;
- }
- }
- return this.parseBalance (result);
- }
-
- async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const request = this.extend ({
- 'venueId': this.options['venueId'],
- 'accountId': await this.getActiveAccount (),
- }, params);
- if (!request['accountId']) {
- throw new ArgumentsRequired (this.id + " fetchMyTrades requires either the 'accountId' extra parameter or exchange.options['accountId'] = 'YOUR_ACCOUNT_ID'.");
- }
- const response = await this.privateGetVenuesVenueIdAccountsAccountIdTrades (request);
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- }
- return this.parseTrades (response['result'], market, since, limit);
- }
-
- async createDepositAddress (code, params = {}) {
- await this.loadMarkets ();
- const paymentMethod = this.safeString (this.options['paymentMethods'], code);
- if (paymentMethod === undefined) {
- throw new NotSupported (this.id + ' createDepositAddress requires code to be BTC, ETH, or XLM');
- }
- const request = this.extend ({
- 'venueId': this.options['venueId'],
- 'accountId': await this.getActiveAccount (),
- 'assetId': this.currencyId (code),
- 'paymentMethod': paymentMethod,
- }, params);
- if (!request['accountId']) {
- throw new ArgumentsRequired (this.id + " createDepositAddress requires either the 'accountId' extra parameter or exchange.options['accountId'] = 'YOUR_ACCOUNT_ID'.");
- }
- const response = await this.privatePostVenuesVenueIdAccountsAccountIdDeposit (request);
- //
- // {
- // assetId: 'BTC/stronghold.co',
- // paymentMethod: 'bitcoin',
- // paymentMethodInstructions: {
- // deposit_address: 'mzMT9Cfw8JXVWK7rMonrpGfY9tt57ytHt4',
- // reference: 'sometimes-exists',
- // },
- // direction: 'deposit',
- // }
- //
- const data = response['result']['paymentMethodInstructions'];
- const address = data['deposit_address'];
- const tag = this.safeString (data, 'reference');
- return {
- 'currency': code,
- 'address': this.checkAddress (address),
- 'tag': tag,
- 'info': response,
- };
- }
-
- async withdraw (code, amount, address, tag = undefined, params = {}) {
- await this.loadMarkets ();
- const paymentMethod = this.safeString (this.options['paymentMethods'], code);
- if (paymentMethod === undefined) {
- throw new NotSupported (this.id + ' withdraw requires code to be BTC, ETH, or XLM');
- }
- const request = this.extend ({
- 'venueId': this.options['venueId'],
- 'accountId': await this.getActiveAccount (),
- 'assetId': this.currencyId (code),
- 'amount': amount,
- 'paymentMethod': paymentMethod,
- 'paymentMethodDetails': {
- 'withdrawal_address': address,
- },
- }, params);
- if (tag !== undefined) {
- request['paymentMethodDetails']['reference'] = tag;
- }
- if (!request['accountId']) {
- throw new ArgumentsRequired (this.id + " withdraw requires either the 'accountId' extra parameter or exchange.options['accountId'] = 'YOUR_ACCOUNT_ID'.");
- }
- const response = await this.privatePostVenuesVenueIdAccountsAccountIdWithdrawal (request);
- //
- // {
- // "id": "5be48892-1b6e-4431-a3cf-34b38811e82c",
- // "assetId": "BTC/stronghold.co",
- // "amount": "10",
- // "feeAmount": "0.01",
- // "paymentMethod": "bitcoin",
- // "paymentMethodDetails": {
- // "withdrawal_address": "1vHysJeXYV6nqhroBaGi52QWFarbJ1dmQ"
- // },
- // "direction": "withdrawal",
- // "status": "pending"
- // }
- //
- const data = response['result'];
- return {
- 'id': this.safeString (data, 'id'),
- 'info': response,
- };
- }
-
- handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
- if (!response) {
- return; // fallback to base error handler by default
- }
- //
- // {
- // requestId: '3e7d17ab-b316-4721-b5aa-f7e6497eeab9',
- // timestamp: '2019-01-31T21:59:06.696855Z',
- // success: true,
- // statusCode: 200,
- // result: []
- // }
- //
- const errorCode = this.safeString (response, 'errorCode');
- if (errorCode in this.exceptions) {
- const Exception = this.exceptions[errorCode];
- throw new Exception (this.id + ' ' + body);
- }
- const success = this.safeValue (response, 'success');
- if (!success) {
- throw new ExchangeError (this.id + ' ' + body);
- }
- }
-
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- const request = '/' + this.version + '/' + this.implodeParams (path, params);
- const query = this.omit (params, this.extractParams (path));
- let url = this.urls['api'][api] + request;
- if (Object.keys (query).length) {
- if (method === 'GET') {
- url += '?' + this.urlencode (query);
- } else {
- body = this.json (query);
- }
- }
- if (api === 'private') {
- this.checkRequiredCredentials ();
- const timestamp = this.nonce ().toString ();
- let payload = timestamp + method + request;
- if (body !== undefined) {
- payload += body;
- }
- const secret = this.base64ToBinary (this.secret);
- headers = {
- 'SH-CRED-ID': this.apiKey,
- 'SH-CRED-SIG': this.hmac (this.encode (payload), secret, 'sha256', 'base64'),
- 'SH-CRED-TIME': timestamp,
- 'SH-CRED-PASS': this.password,
- 'Content-Type': 'application/json',
- };
- }
- return { 'url': url, 'method': method, 'body': body, 'headers': headers };
- }
-};
-
-},{"./base/Exchange":7,"./base/errors":9}],158:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],164:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -104266,922 +123833,7 @@ module.exports = class surbitcoin extends foxbit {
}
};
-},{"./foxbit.js":84}],159:[function(require,module,exports){
-'use strict';
-
-const Exchange = require ('./base/Exchange');
-const { ExchangeError, ExchangeNotAvailable, ArgumentsRequired, BadRequest, AuthenticationError, InvalidOrder, OrderNotFound, NotSupported, OrderNotFillable, InvalidAddress, InsufficientFunds } = require ('./base/errors');
-
-module.exports = class theocean extends Exchange {
- describe () {
- this.checkRequiredDependencies ();
- return this.deepExtend (super.describe (), {
- 'id': 'theocean',
- 'name': 'The Ocean',
- 'countries': [ 'US' ],
- 'rateLimit': 3000,
- 'version': 'v1',
- 'requiresWeb3': true,
- 'timeframes': {
- '5m': '300',
- '15m': '900',
- '1h': '3600',
- '6h': '21600',
- '1d': '86400',
- },
- 'has': {
- 'cancelAllOrders': true,
- 'CORS': false, // ?
- 'fetchClosedOrders': true,
- 'fetchOHLCV': false,
- 'fetchOpenOrders': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchTickers': true,
- },
- 'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/43103756-d56613ce-8ed7-11e8-924e-68f9d4bcacab.jpg',
- 'api': 'https://api.theocean.trade',
- 'www': 'https://theocean.trade',
- 'doc': 'https://docs.theocean.trade',
- 'fees': 'https://theocean.trade/fees',
- },
- 'api': {
- 'public': {
- 'get': [
- 'fee_components',
- 'token_pairs',
- 'ticker',
- 'tickers',
- 'candlesticks',
- 'candlesticks/intervals',
- 'trade_history',
- 'order_book',
- 'order/{orderHash}',
- 'version',
- ],
- },
- 'private': {
- 'get': [
- 'balance',
- 'available_balance',
- 'order_history',
- 'order/unsigned',
- 'order/unsigned/market',
- ],
- 'post': [
- 'order',
- ],
- 'delete': [
- 'order/{orderHash}',
- 'order',
- ],
- },
- },
- 'exceptions': {
- 'exact': {
- 'Order not found': OrderNotFound, // {"message":"Order not found","errors":...}
- },
- 'broad': {
- "Price can't exceed 8 digits in precision.": InvalidOrder, // {"message":"Price can't exceed 8 digits in precision.","type":"paramPrice"}
- 'Order cannot be canceled': InvalidOrder, // {"message":"Order cannot be canceled","type":"General error"}
- 'Greater than available wallet balance.': InsufficientFunds,
- 'Fillable amount under minimum': InvalidOrder, // {"message":"Fillable amount under minimum WETH trade size.","type":"paramQuoteTokenAmount"}
- 'Fillable amount over maximum': InvalidOrder, // {"message":"Fillable amount over maximum TUSD trade size.","type":"paramQuoteTokenAmount"}
- "Schema validation failed for 'params'": BadRequest, // // {"message":"Schema validation failed for 'params'"}
- 'Service Temporarily Unavailable': ExchangeNotAvailable,
- },
- },
- 'options': {
- 'decimals': {},
- 'fetchOrderMethod': 'fetch_order_from_history',
- },
- });
- }
-
- async fetchMarkets (params = {}) {
- const markets = await this.publicGetTokenPairs (params);
- //
- // [
- // "baseToken": {
- // "symbol": "ZRX",
- // "address": "0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570",
- // "name": "0x Protocol Token",
- // "decimals": "18",
- // "minAmount": "10000000000000000000",
- // "maxAmount": "10000000000000000000000",
- // "precision": "-8"
- // },
- // "quoteToken": {
- // "symbol": "ETH",
- // "address": "0xd0a1e359811322d97991e03f863a0c30c2cf029c",
- // "name": "Ether Token",
- // "decimals": "18",
- // "minAmount": "20000000000000000",
- // "maxAmount": "20000000000000000000",
- // "precision": "-8"
- // }
- // ]
- //
- const result = [];
- for (let i = 0; i < markets.length; i++) {
- const market = markets[i];
- const baseToken = this.safeValue (market, 'baseToken', {});
- const quoteToken = this.safeValue (market, 'quoteToken', {});
- const baseId = this.safeString (baseToken, 'address');
- const quoteId = this.safeString (quoteToken, 'address');
- const base = this.safeCurrencyCode (this.safeString (baseToken, 'symbol'));
- const quote = this.safeCurrencyCode (this.safeString (quoteToken, 'symbol'));
- const symbol = base + '/' + quote;
- const id = baseId + '/' + quoteId;
- const baseDecimals = this.safeInteger (baseToken, 'decimals');
- const quoteDecimals = this.safeInteger (quoteToken, 'decimals');
- this.options['decimals'][base] = baseDecimals;
- this.options['decimals'][quote] = quoteDecimals;
- const precision = {
- 'amount': -parseInt (baseToken['precision']),
- 'price': -parseInt (quoteToken['precision']),
- };
- const amountLimits = {
- 'min': this.fromWei (this.safeString (baseToken, 'minAmount'), baseDecimals),
- 'max': this.fromWei (this.safeString (baseToken, 'maxAmount'), baseDecimals),
- };
- const priceLimits = {
- 'min': undefined,
- 'max': undefined,
- };
- const costLimits = {
- 'min': this.fromWei (this.safeString (quoteToken, 'minAmount'), quoteDecimals),
- 'max': this.fromWei (this.safeString (quoteToken, 'maxAmount'), quoteDecimals),
- };
- const limits = {
- 'amount': amountLimits,
- 'price': priceLimits,
- 'cost': costLimits,
- };
- const active = true;
- result.push ({
- 'id': id,
- 'symbol': symbol,
- 'base': base,
- 'quote': quote,
- 'baseId': baseId,
- 'quoteId': quoteId,
- 'active': active,
- 'precision': precision,
- 'limits': limits,
- 'info': market,
- });
- }
- return result;
- }
-
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
- const baseDecimals = this.safeInteger (this.options['decimals'], market['base'], 18);
- return [
- this.safeTimestamp (ohlcv, 'startTime'),
- this.safeFloat (ohlcv, 'open'),
- this.safeFloat (ohlcv, 'high'),
- this.safeFloat (ohlcv, 'low'),
- this.safeFloat (ohlcv, 'close'),
- this.fromWei (this.safeString (ohlcv, 'baseVolume'), baseDecimals),
- ];
- }
-
- async fetchOHLCV (symbol, timeframe = '5m', since = undefined, limit = undefined, params = {}) {
- if (since === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument');
- }
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'baseTokenAddress': market['baseId'],
- 'quoteTokenAddress': market['quoteId'],
- 'interval': this.timeframes[timeframe],
- };
- since = parseInt (since);
- request['startTime'] = since;
- const response = await this.publicGetCandlesticks (this.extend (request, params));
- //
- // [
- // {
- // "high": "100.52",
- // "low": "97.23",
- // "open": "98.45",
- // "close": "99.23",
- // "baseVolume": "2400000000000000000000",
- // "quoteVolume": "1200000000000000000000",
- // "startTime": "1512929323784"
- // },
- // {
- // "high": "100.52",
- // "low": "97.23",
- // "open": "98.45",
- // "close": "99.23",
- // "volume": "2400000000000000000000",
- // "startTime": "1512929198980"
- // }
- // ]
- //
- return this.parseOHLCVs (response, market, timeframe, since, limit);
- }
-
- async fetchBalanceByCode (code, params = {}) {
- if (!this.walletAddress || (this.walletAddress.indexOf ('0x') !== 0)) {
- throw new InvalidAddress (this.id + ' fetchBalanceByCode() requires the .walletAddress to be a "0x"-prefixed hexstring like "0xbF2d65B3b2907214EEA3562f21B80f6Ed7220377"');
- }
- await this.loadMarkets ();
- const currency = this.currency (code);
- const request = {
- 'walletAddress': this.walletAddress.toLowerCase (),
- 'tokenAddress': currency['id'],
- };
- const response = await this.privateGetBalance (this.extend (request, params));
- //
- // {"available":"0","committed":"0","total":"0"}
- //
- const decimals = this.safeInteger (this.options['decimals'], code, 18);
- const free = this.fromWei (this.safeString (response, 'available'), decimals);
- const used = this.fromWei (this.safeString (response, 'committed'), decimals);
- const total = this.fromWei (this.safeString (response, 'total'), decimals);
- return {
- 'free': free,
- 'used': used,
- 'total': total,
- };
- }
-
- async fetchBalance (params = {}) {
- if (!this.walletAddress || (this.walletAddress.indexOf ('0x') !== 0)) {
- throw new InvalidAddress (this.id + ' fetchBalance() requires the .walletAddress to be a "0x"-prefixed hexstring like "0xbF2d65B3b2907214EEA3562f21B80f6Ed7220377"');
- }
- let codes = this.safeValue (this.options, 'fetchBalanceCurrencies');
- if (codes === undefined) {
- codes = this.safeValue (params, 'codes');
- }
- if ((codes === undefined) || (!Array.isArray (codes))) {
- throw new ExchangeError (this.id + ' fetchBalance() requires a `codes` parameter (an array of currency codes)');
- }
- await this.loadMarkets ();
- const result = {};
- for (let i = 0; i < codes.length; i++) {
- const code = codes[i];
- result[code] = await this.fetchBalanceByCode (code);
- }
- return this.parseBalance (result);
- }
-
- parseBidAsk (bidask, priceKey = 0, amountKey = 1, market = undefined) {
- if (market === undefined) {
- throw new ArgumentsRequired (this.id + ' parseBidAsk requires a market argument');
- }
- const price = parseFloat (bidask[priceKey]);
- const amountDecimals = this.safeInteger (this.options['decimals'], market['base'], 18);
- const amount = this.fromWei (bidask[amountKey], 'ether', amountDecimals);
- return [ price, amount ];
- }
-
- parseOrderBook (orderbook, timestamp = undefined, bidsKey = 'bids', asksKey = 'asks', priceKey = 0, amountKey = 1, market = undefined) {
- const result = {
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'nonce': undefined,
- };
- const sides = [ bidsKey, asksKey ];
- for (let i = 0; i < sides.length; i++) {
- const side = sides[i];
- const orders = [];
- const bidasks = this.safeValue (orderbook, side);
- for (let k = 0; k < bidasks.length; k++) {
- orders.push (this.parseBidAsk (bidasks[k], priceKey, amountKey, market));
- }
- result[side] = orders;
- }
- result[bidsKey] = this.sortBy (result[bidsKey], 0, true);
- result[asksKey] = this.sortBy (result[asksKey], 0);
- return result;
- }
-
- async fetchOrderBook (symbol, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'baseTokenAddress': market['baseId'],
- 'quoteTokenAddress': market['quoteId'],
- };
- if (limit !== undefined) {
- request['depth'] = limit;
- }
- const response = await this.publicGetOrderBook (this.extend (request, params));
- //
- // {
- // "bids": [
- // { orderHash: '0xe2b7f80198edb561cc66cd85cb8e5f420073cf1e5143193d8add8774bd8236c4',
- // price: '30',
- // availableAmount: '500000000000000000',
- // creationTimestamp: '1547193525',
- // expirationTimestampInSec: '1549789124'
- // }
- // ],
- // "asks": [
- // { orderHash: '0xe2b7f80198edb561cc66cd85cb8e5f420073cf1e5143193d8add8774bd8236c4',
- // price: '30',
- // availableAmount: '500000000000000000',
- // creationTimestamp: '1547193525',
- // expirationTimestampInSec: '1549789124'
- // }
- // ]
- // }
- //
- return this.parseOrderBook (response, undefined, 'bids', 'asks', 'price', 'availableAmount', market);
- }
-
- parseTicker (ticker, market = undefined) {
- //
- // {
- // "bid": "0.00050915",
- // "ask": "0.00054134",
- // "last": "0.00052718",
- // "volume": "3000000000000000000",
- // "timestamp": "1512929327792"
- // }
- //
- const timestamp = parseInt (this.safeInteger (ticker, 'timestamp') / 1000);
- let symbol = undefined;
- let base = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- base = market['base'];
- }
- const baseDecimals = this.safeInteger (this.options['decimals'], base, 18);
- const baseVolume = this.fromWei (this.safeString (ticker, 'volume'), baseDecimals);
- const last = this.safeFloat (ticker, 'last');
- return {
- 'symbol': symbol,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'high': undefined,
- 'low': undefined,
- 'bid': this.safeFloat (ticker, 'bid'),
- 'bidVolume': undefined,
- 'ask': this.safeFloat (ticker, 'ask'),
- 'askVolume': undefined,
- 'vwap': undefined,
- 'open': undefined,
- 'close': last,
- 'last': last,
- 'previousClose': undefined,
- 'change': undefined,
- 'percentage': this.safeFloat (ticker, 'priceChange'),
- 'average': undefined,
- 'baseVolume': baseVolume,
- 'quoteVolume': undefined,
- 'info': ticker,
- };
- }
-
- async fetchTickers (symbols = undefined, params = {}) {
- await this.loadMarkets ();
- const tickers = await this.publicGetTickers (params);
- //
- // [{
- // "baseTokenAddress": "0xa8e9fa8f91e5ae138c74648c9c304f1c75003a8d",
- // "quoteTokenAddress": "0xc00fd9820cd2898cc4c054b7bf142de637ad129a",
- // "ticker": {
- // "bid": "0.00050915",
- // "ask": "0.00054134",
- // "last": "0.00052718",
- // "volume": "3000000000000000000",
- // "timestamp": "1512929327792"
- // }
- // }]
- //
- const result = {};
- for (let i = 0; i < tickers.length; i++) {
- const ticker = tickers[i];
- const baseId = this.safeString (ticker, 'baseTokenAddress');
- const quoteId = this.safeString (ticker, 'quoteTokenAddress');
- const marketId = baseId + '/' + quoteId;
- let market = undefined;
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
- result[symbol] = this.parseTicker (ticker['ticker'], market);
- }
- return result;
- }
-
- async fetchTicker (symbol, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'baseTokenAddress': market['baseId'],
- 'quoteTokenAddress': market['quoteId'],
- };
- const response = await this.publicGetTicker (this.extend (request, params));
- return this.parseTicker (response, market);
- }
-
- parseTrade (trade, market = undefined) {
- //
- // fetchTrades
- //
- // {
- // "id": "37212",
- // "transactionHash": "0x5e6e75e1aa681b51b034296f62ac19be7460411a2ad94042dd8ba637e13eac0c",
- // "amount": "300000000000000000",
- // "price": "0.00052718",
- // ------- they also have a "confirmed" status here ↓ -----------------
- // "status": "filled", // filled | settled | failed
- // "lastUpdated": "1520265048996"
- // }
- //
- // parseOrder trades (timeline "actions", "fills")
- //
- // { action: "confirmed",
- // amount: "1000000000000000000",
- // intentID: "MARKET_INTENT:90jjw2s7gj90jjw2s7gkjjw2s7gl",
- // txHash: "0x043488fdc3f995bf9e632a32424e41ed126de90f8cb340a1ff006c2a74ca8336",
- // blockNumber: "8094822",
- // timestamp: "1532261686" }
- //
- let timestamp = this.safeInteger (trade, 'lastUpdated');
- if (timestamp !== undefined) {
- timestamp /= 1000;
- }
- const price = this.safeFloat (trade, 'price');
- const id = this.safeString (trade, 'id');
- const side = this.safeString (trade, 'side');
- let symbol = undefined;
- let base = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- base = market['base'];
- }
- const baseDecimals = this.safeInteger (this.options['decimals'], base, 18);
- const amount = this.fromWei (this.safeString (trade, 'amount'), baseDecimals);
- let cost = undefined;
- if (amount !== undefined && price !== undefined) {
- cost = amount * price;
- }
- const takerOrMaker = 'taker';
- return {
- 'id': id,
- 'order': id,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'symbol': symbol,
- 'type': undefined,
- 'side': side,
- 'takerOrMaker': takerOrMaker,
- 'price': price,
- 'amount': amount,
- 'cost': cost,
- 'fee': undefined,
- 'info': trade,
- };
- }
-
- async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'baseTokenAddress': market['baseId'],
- 'quoteTokenAddress': market['quoteId'],
- };
- const response = await this.publicGetTradeHistory (this.extend (request, params));
- //
- // [
- // {
- // "id": "37212",
- // "transactionHash": "0x5e6e75e1aa681b51b034296f62ac19be7460411a2ad94042dd8ba637e13eac0c",
- // "amount": "300000000000000000",
- // "price": "0.00052718",
- // "status": "filled", // filled | settled | failed
- // "lastUpdated": "1520265048996"
- // }
- // ]
- //
- return this.parseTrades (response, market, since, limit);
- }
-
- async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- const errorMessage = this.id + ' createOrder() requires `exchange.walletAddress` and `exchange.privateKey`. The .walletAddress should be a "0x"-prefixed hexstring like "0xbF2d65B3b2907214EEA3562f21B80f6Ed7220377". The .privateKey for that wallet should be a "0x"-prefixed hexstring like "0xe4f40d465efa94c98aec1a51f574329344c772c1bce33be07fa20a56795fdd09".';
- if (!this.walletAddress || (this.walletAddress.indexOf ('0x') !== 0)) {
- throw new InvalidAddress (errorMessage);
- }
- if (!this.privateKey || (this.privateKey.indexOf ('0x') !== 0)) {
- throw new InvalidAddress (errorMessage);
- }
- const orderParams = await this.fetchOrderParamsToSign (symbol, type, side, amount, price, params);
- const unsignedOrder = orderParams['unsignedZeroExOrder'];
- if (unsignedOrder === undefined) {
- throw new OrderNotFillable (this.id + ' ' + type + ' order to ' + side + ' ' + symbol + ' is not fillable at the moment');
- }
- const signedOrder = await this.signZeroExOrderV2 (unsignedOrder, this.privateKey);
- const id = this.safeString (signedOrder, 'orderHash');
- await this.postSignedOrder (signedOrder, orderParams, params);
- const order = await this.fetchOrder (id);
- order['type'] = type;
- return order;
- }
-
- async fetchOrderParamsToSign (symbol, type, side, amount, price = undefined, params = {}) {
- if (side !== 'buy' && side !== 'sell') {
- throw new ExchangeError (side + ' is not valid side param. Use \'buy\' or \'sell\'');
- }
- if (type !== 'market' && type !== 'limit') {
- throw new ExchangeError (type + ' is not valid type param. Use \'market\' or \'limit\'');
- }
- if (type === 'limit' && price === undefined) {
- throw new ExchangeError ('Price is not provided for limit order');
- }
- await this.loadMarkets ();
- const market = this.market (symbol);
- const baseDecimals = this.safeInteger (this.options['decimals'], market['base'], 18);
- const request = {
- 'walletAddress': this.walletAddress.toLowerCase (), // Your Wallet Address
- 'baseTokenAddress': market['baseId'], // Base token address
- 'quoteTokenAddress': market['quoteId'], // Quote token address
- 'side': side, // "buy" or "sell"
- 'amount': this.toWei (this.amountToPrecision (symbol, amount), baseDecimals), // Base token amount in wei
- };
- let method = undefined;
- if (type === 'limit') {
- method = 'privateGetOrderUnsigned';
- request['price'] = this.priceToPrecision (symbol, price);
- } else if (type === 'market') {
- method = 'privateGetOrderUnsignedMarket';
- } else {
- throw new ExchangeError ('Unsupported order type: ' + type);
- }
- const response = await this[method] (this.extend (request, params));
- return response;
- }
-
- async postSignedOrder (signedOrder, requestParams, params = {}) {
- let request = requestParams;
- request['signedZeroExOrder'] = signedOrder;
- request = this.omit (request, 'unsignedZeroExOrder');
- const response = await this.privatePostOrder (this.extend (request, params));
- return response;
- }
-
- async cancelOrder (id, symbol = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'orderHash': id,
- };
- const response = await this.privateDeleteOrderOrderHash (this.extend (request, params));
- //
- // {
- // "canceledOrder": {
- // "orderHash": "0x3d6b287c1dc79262d2391ae2ca9d050fdbbab2c8b3180e4a46f9f321a7f1d7a9",
- // "amount": "100000000000"
- // }
- // }
- //
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- }
- return this.extend (this.parseOrder (response['canceledOrder'], market), {
- 'status': 'canceled',
- });
- }
-
- async cancelAllOrders (symbol = undefined, params = {}) {
- const response = await this.privateDeleteOrder (params);
- //
- // [{
- // "canceledOrder": {
- // "orderHash": "0x3d6b287c1dc79262d2391ae2ca9d050fdbbab2c8b3180e4a46f9f321a7f1d7a9",
- // "amount": "100000000000"
- // }
- // }]
- //
- return response;
- }
-
- parseOrder (order, market = undefined) {
- const zeroExOrder = this.safeValue (order, 'zeroExOrder');
- let id = this.safeString (order, 'orderHash');
- if ((id === undefined) && (zeroExOrder !== undefined)) {
- id = this.safeString (zeroExOrder, 'orderHash');
- }
- const side = this.safeString (order, 'side');
- const type = this.safeString (order, 'type'); // injected from outside
- let timestamp = this.safeInteger (order, 'creationTimestamp');
- if (timestamp !== 'undefined') {
- timestamp = parseInt (timestamp / 1000);
- }
- let symbol = undefined;
- const baseId = this.safeString (order, 'baseTokenAddress');
- const quoteId = this.safeString (order, 'quoteTokenAddress');
- let marketId = undefined;
- if (baseId !== undefined && quoteId !== undefined) {
- marketId = baseId + '/' + quoteId;
- }
- market = this.safeValue (this.markets_by_id, marketId, market);
- let base = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- base = market['base'];
- }
- const baseDecimals = this.safeInteger (this.options['decimals'], base, 18);
- const price = this.safeFloat (order, 'price');
- const filledAmount = this.fromWei (this.safeString (order, 'filledAmount'), baseDecimals);
- const settledAmount = this.fromWei (this.safeString (order, 'settledAmount'), baseDecimals);
- const confirmedAmount = this.fromWei (this.safeString (order, 'confirmedAmount'), baseDecimals);
- const failedAmount = this.fromWei (this.safeString (order, 'failedAmount'), baseDecimals);
- const deadAmount = this.fromWei (this.safeString (order, 'deadAmount'), baseDecimals);
- const prunedAmount = this.fromWei (this.safeString (order, 'prunedAmount'), baseDecimals);
- const amount = this.fromWei (this.safeString (order, 'initialAmount'), baseDecimals);
- const filled = this.sum (filledAmount, settledAmount, confirmedAmount);
- let remaining = undefined;
- let lastTradeTimestamp = undefined;
- const timeline = this.safeValue (order, 'timeline');
- let trades = undefined;
- let status = undefined;
- if (timeline !== undefined) {
- const numEvents = timeline.length;
- if (numEvents > 0) {
- const timelineEventsGroupedByAction = this.groupBy (timeline, 'action');
- if ('error' in timelineEventsGroupedByAction) {
- status = 'failed';
- }
- if ('filled' in timelineEventsGroupedByAction) {
- const fillEvents = this.safeValue (timelineEventsGroupedByAction, 'filled');
- const numFillEvents = fillEvents.length;
- lastTradeTimestamp = this.safeInteger (fillEvents[numFillEvents - 1], 'timestamp');
- lastTradeTimestamp = (lastTradeTimestamp !== undefined) ? lastTradeTimestamp : lastTradeTimestamp;
- trades = [];
- for (let i = 0; i < numFillEvents; i++) {
- const trade = this.parseTrade (this.extend (fillEvents[i], {
- 'price': price,
- }), market);
- trades.push (this.extend (trade, {
- 'order': id,
- 'type': type,
- 'side': side,
- }));
- }
- }
- }
- }
- let cost = undefined;
- if (filled !== undefined) {
- if (remaining === undefined) {
- if (amount !== undefined) {
- remaining = amount - filled;
- }
- }
- if (price !== undefined) {
- cost = filled * price;
- }
- }
- let fee = undefined;
- const feeCost = this.safeString (order, 'feeAmount');
- if (feeCost !== undefined) {
- const feeOption = this.safeString (order, 'feeOption');
- let feeCurrency = undefined;
- if (feeOption === 'feeInNative') {
- if (market !== undefined) {
- feeCurrency = market['base'];
- }
- } else if (feeOption === 'feeInZRX') {
- feeCurrency = 'ZRX';
- } else {
- throw new NotSupported (this.id + ' encountered an unsupported order fee option: ' + feeOption);
- }
- const feeDecimals = this.safeInteger (this.options['decimals'], feeCurrency, 18);
- fee = {
- 'cost': this.fromWei (feeCost, feeDecimals),
- 'currency': feeCurrency,
- };
- }
- const amountPrecision = market ? market['precision']['amount'] : 8;
- if (remaining !== undefined) {
- if (status === undefined) {
- status = 'open';
- const rest = remaining - failedAmount - deadAmount - prunedAmount;
- if (rest < Math.pow (10, -amountPrecision)) {
- status = (filled < amount) ? 'canceled' : 'closed';
- }
- }
- }
- const result = {
- 'info': order,
- 'id': id,
- 'clientOrderId': undefined,
- 'symbol': symbol,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'lastTradeTimestamp': lastTradeTimestamp,
- 'type': type,
- 'side': side,
- 'price': price,
- 'cost': cost,
- 'amount': amount,
- 'remaining': remaining,
- 'filled': filled,
- 'status': status,
- 'fee': fee,
- 'trades': trades,
- 'average': undefined,
- };
- return result;
- }
-
- async fetchOpenOrder (id, symbol = undefined, params = {}) {
- const method = this.options['fetchOrderMethod'];
- return await this[method] (id, symbol, this.extend ({
- 'openAmount': 1,
- }, params));
- }
-
- async fetchClosedOrder (id, symbol = undefined, params = {}) {
- const method = this.options['fetchOrderMethod'];
- return await this[method] (id, symbol, this.extend (params));
- }
-
- async fetchOrderFromHistory (id, symbol = undefined, params = {}) {
- const request = {
- 'orderHash': id,
- };
- const orders = await this.fetchOrders (symbol, undefined, undefined, this.extend (request, params));
- const ordersById = this.indexBy (orders, 'id');
- if (id in ordersById) {
- return ordersById[id];
- }
- throw new OrderNotFound (this.id + ' could not find order ' + id + ' in order history');
- }
-
- async fetchOrderById (id, symbol = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {
- 'orderHash': id,
- };
- const response = await this.publicGetOrderOrderHash (this.extend (request, params));
- // {
- // baseTokenAddress: '0xb18845c260f680d5b9d84649638813e342e4f8c9',
- // quoteTokenAddress: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570',
- // side: 'sell',
- // price: '30',
- // feeTokenAddress: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570',
- // amount: '500000000000000000',
- // created: '1547194003',
- // expires: '1549786003',
- // zeroExOrder: {
- // salt: '71810414258284992779348693906799008280152689028521273772736250669496045815907',
- // maker: '0xfa1a3371bcbfcf3deaa8a6f67784bfbe5b886d7f',
- // taker: '0x77b18613579d49f252bd237ef113884eb37a7090',
- // makerFee: '0',
- // takerFee: '0',
- // orderHash: '0x368540323af55868dd9ce6ac248e6a91d9b7595252ca061c4ada7612b09af1cf',
- // feeRecipient: '0x88a64b5e882e5ad851bea5e7a3c8ba7c523fecbe',
- // makerTokenAmount: '500000000000000000',
- // takerTokenAmount: '14845250714350000000',
- // makerTokenAddress: '0xb18845c260f680d5b9d84649638813e342e4f8c9',
- // takerTokenAddress: '0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570',
- // exchangeContractAddress: '0x35dd2932454449b14cee11a94d3674a936d5d7b2',
- // expirationUnixTimestampSec: '1549789602'
- // },
- // feeAmount: '154749285650000000',
- // feeOption: 'feeInNative',
- // cancelAfter: '1549786003'
- // }
- return this.parseOrder (response);
- }
-
- async fetchOrder (id, symbol = undefined, params = {}) {
- const request = {
- 'orderHash': id,
- };
- const orders = await this.fetchOrders (symbol, undefined, undefined, this.extend (request, params));
- const numOrders = orders.length;
- if (numOrders !== 1) {
- throw new OrderNotFound (this.id + ' order ' + id + ' not found');
- }
- return orders[0];
- }
-
- async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {};
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['baseTokenAddress'] = market['baseId'];
- request['quoteTokenAddress'] = market['quoteId'];
- }
- if (limit !== undefined) {
- request['limit'] = limit;
- }
- const response = await this.privateGetOrderHistory (this.extend (request, params));
- //
- // [
- // {
- // "orderHash": "0x94629386298dee69ae63cd3e414336ae153b3f02cffb9ffc53ad71e166615618",
- // "baseTokenAddress": "0x323b5d4c32345ced77393b3530b1eed0f346429d",
- // "quoteTokenAddress": "0xef7fff64389b814a946f3e92105513705ca6b990",
- // "side": "buy",
- // "openAmount": "10000000000000000000",
- // "filledAmount": "0",
- // "reservedAmount": "0",
- // "settledAmount": "0",
- // "confirmedAmount": "0",
- // "deadAmount": "0",
- // "price": "0.00050915",
- // "timeline": [
- // {
- // "action": "placed",
- // "amount": "10000000000000000000",
- // "timestamp": "1512929327792"
- // }
- // ]
- // }
- // ]
- //
- return this.parseOrders (response, undefined, since, limit);
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const request = {
- 'openAmount': 1, // returns open orders with remaining openAmount >= 1
- };
- return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
- }
-
- async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const request = {
- 'openAmount': 0, // returns closed orders with remaining openAmount === 0
- };
- return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
- }
-
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- let url = this.urls['api'] + '/' + this.version + '/' + this.implodeParams (path, params);
- const query = this.omit (params, this.extractParams (path));
- if (api === 'private') {
- this.checkRequiredCredentials ();
- const timestamp = this.seconds ().toString ();
- let prehash = this.apiKey + timestamp + method;
- if (method === 'POST') {
- body = this.json (query);
- prehash += body;
- } else {
- if (Object.keys (query).length) {
- url += '?' + this.urlencode (query);
- }
- prehash += this.json ({});
- }
- const signature = this.hmac (this.encode (prehash), this.encode (this.secret), 'sha256', 'base64');
- headers = {
- 'TOX-ACCESS-KEY': this.apiKey,
- 'TOX-ACCESS-SIGN': signature,
- 'TOX-ACCESS-TIMESTAMP': timestamp,
- 'Content-Type': 'application/json',
- };
- } else if (api === 'public') {
- if (Object.keys (query).length) {
- url += '?' + this.urlencode (query);
- }
- }
- return { 'url': url, 'method': method, 'body': body, 'headers': headers };
- }
-
- handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
- if (response === undefined) {
- return; // fallback to default error handler
- }
- // code 401 and plain body 'Authentication failed' (with single quotes)
- // this error is sent if you do not submit a proper Content-Type
- if (body === "'Authentication failed'") {
- throw new AuthenticationError (this.id + ' ' + body);
- }
- const message = this.safeString (response, 'message');
- if (message !== undefined) {
- //
- // {"message":"Schema validation failed for 'query'","errors":[{"name":"required","argument":"startTime","message":"requires property \"startTime\"","instance":{"baseTokenAddress":"0x6ff6c0ff1d68b964901f986d4c9fa3ac68346570","quoteTokenAddress":"0xd0a1e359811322d97991e03f863a0c30c2cf029c","interval":"300"},"property":"instance"}]}
- // {"message":"Logic validation failed for 'query'","errors":[{"message":"startTime should be between 0 and current date","type":"startTime"}]}
- // {"message":"Order not found","errors":[]}
- // {"message":"Orderbook exhausted for intent MARKET_INTENT:8yjjzd8b0e8yjjzd8b0fjjzd8b0g"}
- // {"message":"Intent validation failed.","errors":[{"message":"Greater than available wallet balance.","type":"walletBaseTokenAmount"}]}
- // {"message":"Schema validation failed for 'body'","errors":[{"name":"anyOf","argument":["[subschema 0]","[subschema 1]","[subschema 2]"],"message":"is not any of [subschema 0],[subschema 1],[subschema 2]","instance":{"signedTargetOrder":{"error":{"message":"Unsigned target order validation failed.","errors":[{"message":"Greater than available wallet balance.","type":"walletBaseTokenAmount"}]},"maker":"0x1709c02cd7327d391a39a7671af8a91a1ef8a47b","orderHash":"0xda007ea8b5eca71ac96fe4072f7c1209bb151d898a9cc89bbeaa594f0491ee49","ecSignature":{"v":27,"r":"0xb23ce6c4a7b5d51d77e2d00f6d1d472a3b2e72d5b2be1510cfeb122f9366b79e","s":"0x07d274e6d7a00b65fc3026c2f9019215b1e47a5ac4d1f05e03f90550d27109be"}}},"property":"instance"}]}
- // {"message":"Schema validation failed for 'params'","errors":[{"name":"pattern","argument":"^0x[0-9a-fA-F]{64}$","message":"does not match pattern \"^0x[0-9a-fA-F]{64}$\"","instance":"1","property":"instance.orderHash"}]}
- //
- const feedback = this.id + ' ' + body;
- this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
- this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback);
- throw new ExchangeError (feedback); // unknown message
- }
- }
-};
-
-},{"./base/Exchange":7,"./base/errors":9}],160:[function(require,module,exports){
+},{"./foxbit.js":84}],165:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -105200,16 +123852,24 @@ module.exports = class therock extends Exchange {
'rateLimit': 1000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchTickers': true,
- 'fetchMyTrades': true,
- 'fetchLedger': true,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
- 'fetchTransactions': 'emulated',
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': 'emulated',
+ 'fetchWithdrawals': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27766869-75057fa2-5ee9-11e7-9a6f-13e641fa4707.jpg',
@@ -105453,12 +124113,12 @@ module.exports = class therock extends Exchange {
const result = {};
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- const market = this.markets_by_id[id];
+ const market = this.safeMarket (id);
const symbol = market['symbol'];
const ticker = tickers[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -105509,9 +124169,8 @@ module.exports = class therock extends Exchange {
// currency: "EUR",
// trade_id: 440492 } ] }
//
- if (!market) {
- market = this.markets_by_id[trade['fund_id']];
- }
+ const marketId = this.safeString (trade, 'fund_id');
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.parse8601 (this.safeString (trade, 'date'));
const id = this.safeString (trade, 'id');
const orderId = this.safeString (trade, 'order_id');
@@ -105541,10 +124200,6 @@ module.exports = class therock extends Exchange {
'currency': market['quote'],
};
}
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
return {
'info': trade,
'id': id,
@@ -106093,12 +124748,8 @@ module.exports = class therock extends Exchange {
// }
//
const id = this.safeString (order, 'id');
- let symbol = undefined;
const marketId = this.safeString (order, 'fund_id');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const status = this.parseOrderStatus (this.safeString (order, 'status'));
const timestamp = this.parse8601 (this.safeString (order, 'date'));
const type = this.safeString (order, 'type');
@@ -106138,6 +124789,7 @@ module.exports = class therock extends Exchange {
cost = 0;
}
}
+ const stopPrice = this.safeFloat (order, 'conditional_price');
return {
'id': id,
'clientOrderId': undefined,
@@ -106148,8 +124800,10 @@ module.exports = class therock extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -106412,7 +125066,7 @@ module.exports = class therock extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],161:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],166:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -106431,10 +125085,17 @@ module.exports = class tidebit extends Exchange {
'rateLimit': 1000,
'version': 'v2',
'has': {
- 'fetchDepositAddress': true,
+ 'cancelOrder': true,
'CORS': false,
- 'fetchTickers': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchDepositAddress': true,
+ 'fetchMarkets': true,
'fetchOHLCV': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'timeframes': {
@@ -106451,7 +125112,7 @@ module.exports = class tidebit extends Exchange {
'1w': '10080',
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/39034921-e3acf016-4480-11e8-9945-a6086a1082fe.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87460811-1e690280-c616-11ea-8652-69f187305add.jpg',
'api': 'https://www.tidebit.com',
'www': 'https://www.tidebit.com',
'doc': [
@@ -106651,22 +125312,12 @@ module.exports = class tidebit extends Exchange {
const result = {};
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- let market = undefined;
- let symbol = id;
- if (id in this.markets_by_id) {
- market = this.markets_by_id[id];
- symbol = market['symbol'];
- } else {
- const baseId = id.slice (0, 3);
- const quoteId = id.slice (3, 6);
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ const market = this.safeMarket (id);
+ const symbol = market['symbol'];
const ticker = tickers[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -106716,14 +125367,24 @@ module.exports = class tidebit extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1498530360,
+ // 2700.0,
+ // 2700.0,
+ // 2700.0,
+ // 2700.0,
+ // 0.01
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- ohlcv[1],
- ohlcv[2],
- ohlcv[3],
- ohlcv[4],
- ohlcv[5],
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -106744,6 +125405,13 @@ module.exports = class tidebit extends Exchange {
request['timestamp'] = 1800000;
}
const response = await this.publicGetK (this.extend (request, params));
+ //
+ // [
+ // [1498530360,2700.0,2700.0,2700.0,2700.0,0.01],
+ // [1498530420,2700.0,2700.0,2700.0,2700.0,0],
+ // [1498530480,2700.0,2700.0,2700.0,2700.0,0],
+ // ]
+ //
if (response === 'null') {
return [];
}
@@ -106795,13 +125463,8 @@ module.exports = class tidebit extends Exchange {
// ]
// }
//
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- } else {
- const marketId = order['market'];
- symbol = this.markets_by_id[marketId]['symbol'];
- }
+ const marketId = this.safeString (order, 'market');
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const status = this.parseOrderStatus (this.safeString (order, 'state'));
const id = this.safeString (order, 'id');
@@ -106817,6 +125480,7 @@ module.exports = class tidebit extends Exchange {
cost = price * filled;
}
}
+ const average = this.safeFloat (order, 'avg_price');
return {
'id': id,
'clientOrderId': undefined,
@@ -106826,8 +125490,10 @@ module.exports = class tidebit extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': filled,
'remaining': remaining,
@@ -106835,7 +125501,7 @@ module.exports = class tidebit extends Exchange {
'trades': undefined,
'fee': undefined,
'info': order,
- 'average': undefined,
+ 'average': average,
};
}
@@ -106851,8 +125517,7 @@ module.exports = class tidebit extends Exchange {
request['price'] = price.toString ();
}
const response = await this.privatePostOrders (this.extend (request, params));
- const market = this.markets_by_id[response['market']];
- return this.parseOrder (response, market);
+ return this.parseOrder (response);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -106945,7 +125610,7 @@ module.exports = class tidebit extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],162:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],167:[function(require,module,exports){
'use strict';
const Exchange = require ('./base/Exchange');
@@ -106961,17 +125626,22 @@ module.exports = class tidex extends Exchange {
'version': '3',
'userAgent': this.userAgents['chrome'],
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createMarketOrder': false,
- 'fetchOrderBooks': true,
- 'fetchOrder': true,
- 'fetchOrders': 'emulated',
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': 'emulated',
- 'fetchTickers': true,
- 'fetchMyTrades': true,
- 'withdraw': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchCurrencies': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrderBooks': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/30781780-03149dc4-a12e-11e7-82bb-313b269d24d4.jpg',
@@ -107064,6 +125734,7 @@ module.exports = class tidex extends Exchange {
'options': {
'fetchTickersMaxLength': 2048,
},
+ 'orders': {}, // orders cache / emulation
});
}
@@ -107254,10 +125925,7 @@ module.exports = class tidex extends Exchange {
ids = Object.keys (response);
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- let symbol = id;
- if (id in this.markets_by_id) {
- symbol = this.markets_by_id[id]['symbol'];
- }
+ const symbol = this.safeSymbol (id);
result[symbol] = this.parseOrderBook (response[id]);
}
return result;
@@ -107331,15 +125999,11 @@ module.exports = class tidex extends Exchange {
const keys = Object.keys (response);
for (let i = 0; i < keys.length; i++) {
const id = keys[i];
- let symbol = id;
- let market = undefined;
- if (id in this.markets_by_id) {
- market = this.markets_by_id[id];
- symbol = market['symbol'];
- }
+ const market = this.safeMarket (id);
+ const symbol = market['symbol'];
result[symbol] = this.parseTicker (response[id], market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -107358,14 +126022,8 @@ module.exports = class tidex extends Exchange {
const price = this.safeFloat2 (trade, 'rate', 'price');
const id = this.safeString2 (trade, 'trade_id', 'tid');
const orderId = this.safeString (trade, 'order_id');
- if ('pair' in trade) {
- const marketId = this.safeString (trade, 'pair');
- market = this.safeValue (this.markets_by_id, marketId, market);
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (trade, 'pair');
+ const symbol = this.safeSymbol (marketId, market);
const amount = this.safeFloat (trade, 'amount');
const type = 'limit'; // all trades are still limit trades
let takerOrMaker = undefined;
@@ -107460,7 +126118,7 @@ module.exports = class tidex extends Exchange {
remaining = this.safeFloat (response['return'], 'remains', amount);
}
const timestamp = this.milliseconds ();
- const order = {
+ return {
'id': id,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
@@ -107481,8 +126139,6 @@ module.exports = class tidex extends Exchange {
'average': undefined,
'trades': undefined,
};
- this.orders[id] = order;
- return order;
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -107490,11 +126146,7 @@ module.exports = class tidex extends Exchange {
const request = {
'order_id': parseInt (id),
};
- const response = await this.privatePostCancelOrder (this.extend (request, params));
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- }
- return response;
+ return await this.privatePostCancelOrder (this.extend (request, params));
}
parseOrderStatus (status) {
@@ -107511,16 +126163,8 @@ module.exports = class tidex extends Exchange {
const id = this.safeString (order, 'id');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
const timestamp = this.safeTimestamp (order, 'timestamp_created');
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'pair');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'pair');
+ const symbol = this.safeSymbol (marketId, market);
let remaining = undefined;
let amount = undefined;
const price = this.safeFloat (order, 'rate');
@@ -107531,9 +126175,6 @@ module.exports = class tidex extends Exchange {
remaining = this.safeFloat (order, 'amount');
} else {
remaining = this.safeFloat (order, 'amount');
- if (id in this.orders) {
- amount = this.orders[id]['amount'];
- }
}
if (amount !== undefined) {
if (remaining !== undefined) {
@@ -107545,40 +126186,27 @@ module.exports = class tidex extends Exchange {
return {
'info': order,
'id': id,
+ 'clientOrderId': undefined,
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'type': 'limit',
- 'side': order['type'],
+ 'timeInForce': undefined,
+ 'side': this.safeString (order, 'type'),
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'remaining': remaining,
'filled': filled,
'status': status,
'fee': fee,
- 'clientOrderId': undefined,
'average': undefined,
'trades': undefined,
};
}
- parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
- const result = [];
- const ids = Object.keys (orders);
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- for (let i = 0; i < ids.length; i++) {
- const id = ids[i];
- const order = this.extend ({ 'id': id }, orders[id]);
- result.push (this.extend (this.parseOrder (order, market), params));
- }
- return this.filterBySymbolSinceLimit (result, symbol, since, limit);
- }
-
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const request = {
@@ -107586,62 +126214,12 @@ module.exports = class tidex extends Exchange {
};
const response = await this.privatePostOrderInfo (this.extend (request, params));
id = id.toString ();
- const newOrder = this.parseOrder (this.extend ({ 'id': id }, response['return'][id]));
- const oldOrder = (id in this.orders) ? this.orders[id] : {};
- this.orders[id] = this.extend (oldOrder, newOrder);
- return this.orders[id];
+ const result = this.safeValue (response, 'return', {});
+ const order = this.safeValue (result, id);
+ return this.parseOrder (this.extend ({ 'id': id }, order));
}
- updateCachedOrders (openOrders, symbol) {
- // update local cache with open orders
- // this will add unseen orders and overwrite existing ones
- for (let j = 0; j < openOrders.length; j++) {
- const id = openOrders[j]['id'];
- this.orders[id] = openOrders[j];
- }
- const openOrdersIndexedById = this.indexBy (openOrders, 'id');
- const cachedOrderIds = Object.keys (this.orders);
- for (let k = 0; k < cachedOrderIds.length; k++) {
- // match each cached order to an order in the open orders array
- // possible reasons why a cached order may be missing in the open orders array:
- // - order was closed or canceled -> update cache
- // - symbol mismatch (e.g. cached BTC/USDT, fetched ETH/USDT) -> skip
- const cachedOrderId = cachedOrderIds[k];
- let cachedOrder = this.orders[cachedOrderId];
- if (!(cachedOrderId in openOrdersIndexedById)) {
- // cached order is not in open orders array
- // if we fetched orders by symbol and it doesn't match the cached order -> won't update the cached order
- if (symbol !== undefined && symbol !== cachedOrder['symbol']) {
- continue;
- }
- // cached order is absent from the list of open orders -> mark the cached order as closed
- if (cachedOrder['status'] === 'open') {
- cachedOrder = this.extend (cachedOrder, {
- 'status': 'closed', // likewise it might have been canceled externally (unnoticed by "us")
- 'cost': undefined,
- 'filled': cachedOrder['amount'],
- 'remaining': 0.0,
- });
- if (cachedOrder['cost'] === undefined) {
- if (cachedOrder['filled'] !== undefined) {
- cachedOrder['cost'] = cachedOrder['filled'] * cachedOrder['price'];
- }
- }
- this.orders[cachedOrderId] = cachedOrder;
- }
- }
- }
- return this.toArray (this.orders);
- }
-
- async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- if ('fetchOrdersRequiresSymbol' in this.options) {
- if (this.options['fetchOrdersRequiresSymbol']) {
- if (symbol === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchOrders requires a `symbol` argument');
- }
- }
- }
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
let market = undefined;
@@ -107650,22 +126228,30 @@ module.exports = class tidex extends Exchange {
request['pair'] = market['id'];
}
const response = await this.privatePostActiveOrders (this.extend (request, params));
+ //
+ // {
+ // "success":1,
+ // "return":{
+ // "1255468911":{
+ // "status":0,
+ // "pair":"spike_usdt",
+ // "type":"sell",
+ // "amount":35028.44256388,
+ // "rate":0.00199989,
+ // "timestamp_created":1602684432
+ // }
+ // },
+ // "stat":{
+ // "isSuccess":true,
+ // "serverTime":"00:00:00.0000826",
+ // "time":"00:00:00.0091423",
+ // "errors":null
+ // }
+ // }
+ //
// it can only return 'open' orders (i.e. no way to fetch 'closed' orders)
const orders = this.safeValue (response, 'return', []);
- const openOrders = this.parseOrders (orders, market);
- const allOrders = this.updateCachedOrders (openOrders, symbol);
- const result = this.filterBySymbol (allOrders, symbol);
- return this.filterBySinceLimit (result, since, limit);
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const orders = await this.fetchOrders (symbol, since, limit, params);
- return this.filterBy (orders, 'status', 'open');
- }
-
- async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const orders = await this.fetchOrders (symbol, since, limit, params);
- return this.filterBy (orders, 'status', 'closed');
+ return this.parseOrders (orders, market, since, limit);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -107808,7 +126394,7 @@ module.exports = class tidex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],163:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],168:[function(require,module,exports){
'use strict';
const Exchange = require ('./base/Exchange');
@@ -107823,16 +126409,23 @@ module.exports = class timex extends Exchange {
'version': 'v1',
'rateLimit': 1500,
'has': {
- 'CORS': false,
+ 'cancelOrder': true,
'cancelOrders': true,
+ 'CORS': false,
+ 'createOrder': true,
'editOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
'fetchCurrencies': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTradingFee': true, // maker fee only
},
'timeframes': {
@@ -108786,22 +127379,8 @@ module.exports = class timex extends Exchange {
// "volumeQuote": 0.07312
// }
//
- let symbol = undefined;
const marketId = this.safeString (ticker, 'market');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('/');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '/');
const timestamp = this.parse8601 (this.safeString (ticker, 'timestamp'));
const last = this.safeFloat (ticker, 'last');
const open = this.safeFloat (ticker, 'open');
@@ -108866,15 +127445,8 @@ module.exports = class timex extends Exchange {
// "timestamp": "2019-12-08T04:54:11.171Z"
// }
//
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.parse8601 (this.safeString (trade, 'timestamp'));
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'quantity');
@@ -108915,7 +127487,7 @@ module.exports = class timex extends Exchange {
};
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// "timestamp":"2019-12-04T23:00:00",
@@ -108961,15 +127533,8 @@ module.exports = class timex extends Exchange {
const id = this.safeString (order, 'id');
const type = this.safeStringLower (order, 'type');
const side = this.safeStringLower (order, 'side');
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.parse8601 (this.safeString (order, 'createdAt'));
const price = this.safeFloat (order, 'price');
const amount = this.safeFloat (order, 'quantity');
@@ -109013,8 +127578,10 @@ module.exports = class timex extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': undefined,
@@ -109033,7 +127600,7 @@ module.exports = class timex extends Exchange {
}
if (api !== 'public') {
this.checkRequiredCredentials ();
- const auth = this.stringToBase64 (this.encode (this.apiKey + ':' + this.secret));
+ const auth = this.stringToBase64 (this.apiKey + ':' + this.secret);
const secret = 'Basic ' + this.decode (auth);
headers = { 'authorization': secret };
}
@@ -109064,34 +127631,7 @@ module.exports = class timex extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],164:[function(require,module,exports){
-'use strict';
-
-// ---------------------------------------------------------------------------
-
-const bw = require ('./bw.js');
-
-// ---------------------------------------------------------------------------
-
-module.exports = class topq extends bw {
- describe () {
- return this.deepExtend (super.describe (), {
- 'id': 'topq',
- 'countries': [ 'SG' ],
- 'name': 'TOP.Q',
- 'hostname': 'topliq.com',
- 'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/74596147-50247000-505c-11ea-9224-4fd347cfbb49.jpg',
- 'api': 'https://www.{hostname}',
- 'www': 'https://www.topliq.com',
- 'doc': 'https://github.com/topq-exchange/api_docs_en/wiki/REST_api_reference',
- 'fees': 'https://www.topliq.com/feesRate',
- },
- });
- }
-};
-
-},{"./bw.js":55}],165:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],169:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -109113,22 +127653,29 @@ module.exports = class upbit extends Exchange {
'pro': true,
// new metainfo interface
'has': {
+ 'cancelOrder': true,
'CORS': true,
'createDepositAddress': true,
'createMarketOrder': true,
- 'fetchDepositAddress': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
'fetchMyTrades': false,
'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrderBooks': true,
'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrderBooks': true,
'fetchOrders': false,
+ 'fetchTicker': true,
'fetchTickers': true,
- 'withdraw': true,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
+ 'fetchTrades': true,
'fetchTransactions': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': 'minutes',
@@ -109237,11 +127784,13 @@ module.exports = class upbit extends Exchange {
'createMarketBuyOrderRequiresPrice': true,
'fetchTickersMaxLength': 4096, // 2048,
'fetchOrderBooksMaxLength': 4096, // 2048,
- 'symbolSeparator': '-',
'tradingFeesByQuoteCurrency': {
'KRW': 0.0005,
},
},
+ 'commonCurrencies': {
+ 'TON': 'Tokamak Network',
+ },
});
}
@@ -109526,20 +128075,6 @@ module.exports = class upbit extends Exchange {
return this.parseBalance (result);
}
- getSymbolFromMarketId (marketId, market = undefined) {
- if (marketId === undefined) {
- return undefined;
- }
- market = this.safeValue (this.markets_by_id, marketId, market);
- if (market !== undefined) {
- return market['symbol'];
- }
- const [ baseId, quoteId ] = marketId.split (this.options['symbolSeparator']);
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- return base + '/' + quote;
- }
-
async fetchOrderBooks (symbols = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
let ids = undefined;
@@ -109589,7 +128124,8 @@ module.exports = class upbit extends Exchange {
const result = {};
for (let i = 0; i < response.length; i++) {
const orderbook = response[i];
- const symbol = this.getSymbolFromMarketId (this.safeString (orderbook, 'market'));
+ const marketId = this.safeString (orderbook, 'market');
+ const symbol = this.safeSymbol (marketId, undefined, '-');
const timestamp = this.safeInteger (orderbook, 'timestamp');
result[symbol] = {
'bids': this.sortBy (this.parseBidsAsks (orderbook['orderbook_units'], 'bid_price', 'bid_size'), 0, true),
@@ -109637,7 +128173,8 @@ module.exports = class upbit extends Exchange {
// timestamp: 1542883543813 }
//
const timestamp = this.safeInteger (ticker, 'trade_timestamp');
- const symbol = this.getSymbolFromMarketId (this.safeString2 (ticker, 'market', 'code'), market);
+ const marketId = this.safeString2 (ticker, 'market', 'code');
+ const symbol = this.safeSymbol (marketId, market, '-');
const previous = this.safeFloat (ticker, 'prev_closing_price');
const last = this.safeFloat (ticker, 'trade_price');
const change = this.safeFloat (ticker, 'signed_change_price');
@@ -109718,7 +128255,7 @@ module.exports = class upbit extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -109779,7 +128316,7 @@ module.exports = class upbit extends Exchange {
}
}
const marketId = this.safeString2 (trade, 'market', 'code');
- market = this.safeValue (this.markets_by_id, marketId, market);
+ market = this.safeMarket (marketId, market);
let fee = undefined;
let feeCurrency = undefined;
let symbol = undefined;
@@ -109807,7 +128344,7 @@ module.exports = class upbit extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'symbol': symbol,
- 'type': 'limit',
+ 'type': undefined,
'side': side,
'takerOrMaker': undefined,
'price': price,
@@ -109853,19 +128390,21 @@ module.exports = class upbit extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
- // { market: "BTC-ETH",
- // candle_date_time_utc: "2018-11-22T13:47:00",
- // candle_date_time_kst: "2018-11-22T22:47:00",
- // opening_price: 0.02915963,
- // high_price: 0.02915963,
- // low_price: 0.02915448,
- // trade_price: 0.02915448,
- // timestamp: 1542894473674,
- // candle_acc_trade_price: 0.0981629437535248,
- // candle_acc_trade_volume: 3.36693173,
- // unit: 1 },
+ // {
+ // market: "BTC-ETH",
+ // candle_date_time_utc: "2018-11-22T13:47:00",
+ // candle_date_time_kst: "2018-11-22T22:47:00",
+ // opening_price: 0.02915963,
+ // high_price: 0.02915963,
+ // low_price: 0.02915448,
+ // trade_price: 0.02915448,
+ // timestamp: 1542894473674,
+ // candle_acc_trade_price: 0.0981629437535248,
+ // candle_acc_trade_volume: 3.36693173,
+ // unit: 1
+ // }
//
return [
this.parse8601 (this.safeString (ohlcv, 'candle_date_time_utc')),
@@ -109902,28 +128441,34 @@ module.exports = class upbit extends Exchange {
}
const response = await this[method] (this.extend (request, params));
//
- // [ { market: "BTC-ETH",
- // candle_date_time_utc: "2018-11-22T13:47:00",
- // candle_date_time_kst: "2018-11-22T22:47:00",
- // opening_price: 0.02915963,
- // high_price: 0.02915963,
- // low_price: 0.02915448,
- // trade_price: 0.02915448,
- // timestamp: 1542894473674,
- // candle_acc_trade_price: 0.0981629437535248,
- // candle_acc_trade_volume: 3.36693173,
- // unit: 1 },
- // { market: "BTC-ETH",
- // candle_date_time_utc: "2018-11-22T10:06:00",
- // candle_date_time_kst: "2018-11-22T19:06:00",
- // opening_price: 0.0294,
- // high_price: 0.02940882,
- // low_price: 0.02934283,
- // trade_price: 0.02937354,
- // timestamp: 1542881219276,
- // candle_acc_trade_price: 0.0762597110943884,
- // candle_acc_trade_volume: 2.5949617,
- // unit: 1 } ]
+ // [
+ // {
+ // market: "BTC-ETH",
+ // candle_date_time_utc: "2018-11-22T13:47:00",
+ // candle_date_time_kst: "2018-11-22T22:47:00",
+ // opening_price: 0.02915963,
+ // high_price: 0.02915963,
+ // low_price: 0.02915448,
+ // trade_price: 0.02915448,
+ // timestamp: 1542894473674,
+ // candle_acc_trade_price: 0.0981629437535248,
+ // candle_acc_trade_volume: 3.36693173,
+ // unit: 1
+ // },
+ // {
+ // market: "BTC-ETH",
+ // candle_date_time_utc: "2018-11-22T10:06:00",
+ // candle_date_time_kst: "2018-11-22T19:06:00",
+ // opening_price: 0.0294,
+ // high_price: 0.02940882,
+ // low_price: 0.02934283,
+ // trade_price: 0.02937354,
+ // timestamp: 1542881219276,
+ // candle_acc_trade_price: 0.0762597110943884,
+ // candle_acc_trade_volume: 2.5949617,
+ // unit: 1
+ // }
+ // ]
//
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -110247,22 +128792,13 @@ module.exports = class upbit extends Exchange {
let average = undefined;
let fee = undefined;
let feeCost = this.safeFloat (order, 'paid_fee');
- let feeCurrency = undefined;
const marketId = this.safeString (order, 'market');
- market = this.safeValue (this.markets_by_id, marketId);
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- feeCurrency = market['quote'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- feeCurrency = quote;
- }
+ market = this.safeMarket (marketId, market);
let trades = this.safeValue (order, 'trades', []);
- trades = this.parseTrades (trades, market, undefined, undefined, { 'order': id });
+ trades = this.parseTrades (trades, market, undefined, undefined, {
+ 'order': id,
+ 'type': type,
+ });
const numTrades = trades.length;
if (numTrades > 0) {
// the timestamp in fetchOrder trades is missing
@@ -110288,7 +128824,7 @@ module.exports = class upbit extends Exchange {
}
if (feeCost !== undefined) {
fee = {
- 'currency': feeCurrency,
+ 'currency': market['quote'],
'cost': feeCost,
};
}
@@ -110299,10 +128835,12 @@ module.exports = class upbit extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -110600,7 +129138,7 @@ module.exports = class upbit extends Exchange {
return; // fallback to default error handler
}
//
- // { 'error': { 'message': "Missing request parameter error. Check the required parameters!", 'name': 400 } },
+ // { 'error': { 'message': "Missing request parameter error. Check the required parameters!", 'name': 400 } },
// { 'error': { 'message': "side is missing, side does not have a valid value", 'name': "validation_error" } },
// { 'error': { 'message': "개인정보 제 3자 제공 동의가 필요합니다.", 'name': "thirdparty_agreement_required" } },
// { 'error': { 'message': "권한이 부족합니다.", 'name': "out_of_scope" } },
@@ -110624,7 +129162,7 @@ module.exports = class upbit extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],166:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],170:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -110829,7 +129367,7 @@ module.exports = class vaultoro extends Exchange {
}
};
-},{"./base/Exchange":7}],167:[function(require,module,exports){
+},{"./base/Exchange":5}],171:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -110863,7 +129401,3015 @@ module.exports = class vbtc extends foxbit {
}
};
-},{"./foxbit.js":84}],168:[function(require,module,exports){
+},{"./foxbit.js":84}],172:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, OrderNotFound, InvalidOrder, BadRequest, AuthenticationError, RateLimitExceeded, RequestTimeout, BadSymbol, AddressPending, PermissionDenied, InsufficientFunds } = require ('./base/errors');
+const { ROUND } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class vcc extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'vcc',
+ 'name': 'VCC Exchange',
+ 'countries': [ 'VN' ], // Vietnam
+ 'rateLimit': 1000,
+ 'version': 'v3',
+ 'has': {
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'editOrder': false,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchTicker': 'emulated',
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTradingFees': false,
+ 'fetchTransactions': true,
+ 'fetchWithdrawals': true,
+ },
+ 'timeframes': {
+ '1m': '60000',
+ '5m': '300000',
+ '15m': '900000',
+ '30m': '1800000',
+ '1h': '3600000',
+ '2h': '7200000',
+ '4h': '14400000',
+ '6h': '21600000',
+ '12h': '43200000',
+ '1d': '86400000',
+ '1w': '604800000',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/100545356-8427f500-326c-11eb-9539-7d338242d61b.jpg',
+ 'api': {
+ 'public': 'https://api.vcc.exchange',
+ 'private': 'https://api.vcc.exchange',
+ },
+ 'www': 'https://vcc.exchange',
+ 'doc': [
+ 'https://vcc.exchange/api',
+ ],
+ 'fees': 'https://support.vcc.exchange/hc/en-us/articles/360016401754',
+ 'referral': 'https://vcc.exchange?ref=l4xhrH',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'summary',
+ 'exchange_info',
+ 'assets', // Available Currencies
+ 'ticker', // Ticker list for all symbols
+ 'trades/{market_pair}', // Recent trades
+ 'orderbook/{market_pair}', // Orderbook
+ 'chart/bars', // Candles
+ 'tick_sizes',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'user',
+ 'balance', // Get trading balance
+ 'orders/{order_id}', // Get a single order by order_id
+ 'orders/open', // Get open orders
+ 'orders', // Get closed orders
+ 'orders/trades', // Get trades history
+ 'deposit-address', // Generate or get deposit address
+ 'transactions', // Get deposit/withdrawal history
+ ],
+ 'post': [
+ 'orders', // Create new order
+ ],
+ 'put': [
+ 'orders/{order_id}/cancel', // Cancel order
+ 'orders/cancel-by-type',
+ 'orders/cancel-all',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': false,
+ 'percentage': true,
+ 'maker': 0.2 / 100,
+ 'taker': 0.2 / 100,
+ },
+ },
+ 'exceptions': {
+ 'exact': {},
+ 'broad': {
+ 'limit may not be greater than': BadRequest, // {"message":"The given data was invalid.","errors":{"limit":["The limit may not be greater than 1000."]}}
+ 'Insufficient balance': InsufficientFunds, // {"message":"Insufficient balance."}
+ 'Unauthenticated': AuthenticationError, // {"message":"Unauthenticated."} // wrong api key
+ 'signature is invalid': AuthenticationError, // {"message":"The given data was invalid.","errors":{"signature":["HMAC signature is invalid"]}}
+ 'Timeout': RequestTimeout, // {"code":504,"message":"Gateway Timeout","description":""}
+ 'Too many requests': RateLimitExceeded, // {"code":429,"message":"Too many requests","description":"Too many requests"}
+ 'quantity field is required': InvalidOrder, // {"message":"The given data was invalid.","errors":{"quantity":["The quantity field is required when type is market."]}}
+ 'price field is required': InvalidOrder, // {"message":"The given data was invalid.","errors":{"price":["The price field is required when type is limit."]}}
+ 'error_security_level': PermissionDenied, // {"message":"error_security_level"}
+ 'pair is invalid': BadSymbol, // {"message":"The given data was invalid.","errors":{"coin":["Trading pair is invalid","Trading pair is offline"]}}
+ // {"message":"The given data was invalid.","errors":{"type":["The selected type is invalid."]}}
+ // {"message":"The given data was invalid.","errors":{"trade_type":["The selected trade type is invalid."]}}
+ 'type is invalid': InvalidOrder,
+ 'Data not found': OrderNotFound, // {"message":"Data not found"}
+ },
+ },
+ });
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetExchangeInfo (params);
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"4677e56a42f0c29872f3a6e75f5d39d2f07c748c",
+ // "data":{
+ // "timezone":"UTC",
+ // "serverTime":1605821914333,
+ // "symbols":[
+ // {
+ // "id":"btcvnd",
+ // "symbol":"BTC\/VND",
+ // "coin":"btc",
+ // "currency":"vnd",
+ // "baseId":1,
+ // "quoteId":0,
+ // "active":true,
+ // "base_precision":"0.0000010000",
+ // "quote_precision":"1.0000000000",
+ // "minimum_quantity":"0.0000010000",
+ // "minimum_amount":"250000.0000000000",
+ // "precision":{"price":0,"amount":6,"cost":6},
+ // "limits":{
+ // "amount":{"min":"0.0000010000"},
+ // "price":{"min":"1.0000000000"},
+ // "cost":{"min":"250000.0000000000"},
+ // },
+ // },
+ // ],
+ // },
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const markets = this.safeValue (data, 'symbols');
+ const result = [];
+ for (let i = 0; i < markets.length; i++) {
+ const market = this.safeValue (markets, i);
+ const symbol = this.safeString (market, 'symbol');
+ const id = symbol.replace ('/', '_');
+ const baseId = this.safeString (market, 'coin');
+ const quoteId = this.safeString (market, 'currency');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const active = this.safeValue (market, 'active');
+ const precision = this.safeValue (market, 'precision', {});
+ const limits = this.safeValue (market, 'limits', {});
+ const amountLimits = this.safeValue (limits, 'amount', {});
+ const priceLimits = this.safeValue (limits, 'price', {});
+ const costLimits = this.safeValue (limits, 'cost', {});
+ const entry = {
+ 'info': market,
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'active': active,
+ 'precision': {
+ 'price': this.safeInteger (precision, 'price'),
+ 'amount': this.safeInteger (precision, 'amount'),
+ 'cost': this.safeInteger (precision, 'cost'),
+ },
+ 'limits': {
+ 'amount': {
+ 'min': this.safeFloat (amountLimits, 'min'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': this.safeFloat (priceLimits, 'min'),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': this.safeFloat (costLimits, 'min'),
+ 'max': undefined,
+ },
+ },
+ };
+ result.push (entry);
+ }
+ return result;
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetAssets (params);
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"2514c8012d94ea375018fc13e0b5d4d896e435df",
+ // "data":{
+ // "BTC":{
+ // "name":"Bitcoin",
+ // "unified_cryptoasset_id":1,
+ // "can_withdraw":1,
+ // "can_deposit":1,
+ // "min_withdraw":"0.0011250000",
+ // "max_withdraw":"100.0000000000",
+ // "maker_fee":"0.002",
+ // "taker_fee":"0.002",
+ // "decimal":8,
+ // "withdrawal_fee":"0.0006250000",
+ // },
+ // },
+ // }
+ //
+ const result = {};
+ const data = this.safeValue (response, 'data');
+ const ids = Object.keys (data);
+ for (let i = 0; i < ids.length; i++) {
+ const id = this.safeStringLower (ids, i);
+ const currency = this.safeValue (data, ids[i]);
+ const code = this.safeCurrencyCode (id);
+ const canDeposit = this.safeValue (currency, 'can_deposit');
+ const canWithdraw = this.safeValue (currency, 'can_withdraw');
+ const active = (canDeposit && canWithdraw);
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'name': this.safeString (currency, 'name'),
+ 'active': active,
+ 'fee': this.safeFloat (currency, 'withdrawal_fee'),
+ 'precision': this.safeInteger (currency, 'decimal'),
+ 'limits': {
+ 'withdraw': {
+ 'min': this.safeFloat (currency, 'min_withdraw'),
+ 'max': this.safeFloat (currency, 'max_withdraw'),
+ },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchTradingFee (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = this.extend ({
+ 'symbol': market['id'],
+ }, this.omit (params, 'symbol'));
+ const response = await this.privateGetTradingFeeSymbol (request);
+ //
+ // {
+ // takeLiquidityRate: '0.001',
+ // provideLiquidityRate: '-0.0001'
+ // }
+ //
+ return {
+ 'info': response,
+ 'maker': this.safeFloat (response, 'provideLiquidityRate'),
+ 'taker': this.safeFloat (response, 'takeLiquidityRate'),
+ };
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetBalance (params);
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"7168e6c99e90f60673070944d987988eef7d91fa",
+ // "data":{
+ // "vnd":{"balance":0,"available_balance":0},
+ // "btc":{"balance":0,"available_balance":0},
+ // "eth":{"balance":0,"available_balance":0},
+ // },
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const result = { 'info': response };
+ const currencyIds = Object.keys (data);
+ for (let i = 0; i < currencyIds.length; i++) {
+ const currencyId = currencyIds[i];
+ const code = this.safeCurrencyCode (currencyId);
+ const balance = this.safeValue (data, currencyId);
+ const account = this.account ();
+ account['free'] = this.safeFloat (balance, 'available_balance');
+ account['total'] = this.safeFloat (balance, 'balance');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "low":"415805323.0000000000",
+ // "high":"415805323.0000000000",
+ // "open":"415805323.0000000000",
+ // "close":"415805323.0000000000",
+ // "time":"1605845940000",
+ // "volume":"0.0065930000",
+ // "opening_time":1605845963263,
+ // "closing_time":1605845963263
+ // }
+ //
+ return [
+ this.safeInteger (ohlcv, 'time'),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'volume'),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'coin': market['baseId'],
+ 'currency': market['quoteId'],
+ 'resolution': this.timeframes[timeframe],
+ };
+ limit = (limit === undefined) ? 100 : limit;
+ limit = Math.min (100, limit);
+ const duration = this.parseTimeframe (timeframe);
+ if (since === undefined) {
+ const end = this.seconds ();
+ request['to'] = end;
+ request['from'] = end - limit * duration;
+ } else {
+ const start = parseInt (since / 1000);
+ request['from'] = start;
+ request['to'] = this.sum (start, limit * duration);
+ }
+ const response = await this.publicGetChartBars (this.extend (request, params));
+ //
+ // [
+ // {"low":"415805323.0000000000","high":"415805323.0000000000","open":"415805323.0000000000","close":"415805323.0000000000","time":"1605845940000","volume":"0.0065930000","opening_time":1605845963263,"closing_time":1605845963263},
+ // {"low":"416344148.0000000000","high":"416344148.0000000000","open":"415805323.0000000000","close":"416344148.0000000000","time":"1605846000000","volume":"0.0052810000","opening_time":1605846011490,"closing_time":1605846011490},
+ // {"low":"416299269.0000000000","high":"417278376.0000000000","open":"416344148.0000000000","close":"417278376.0000000000","time":"1605846060000","volume":"0.0136750000","opening_time":1605846070727,"closing_time":1605846102282},
+ // ]
+ //
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market_pair': market['id'],
+ // 'depth': 0, // 0 = full orderbook, 5, 10, 20, 50, 100, 500
+ 'level': 2, // 1 = best bidask, 2 = aggregated by price, 3 = no aggregation
+ };
+ if (limit !== undefined) {
+ if ((limit !== 0) && (limit !== 5) && (limit !== 10) && (limit !== 20) && (limit !== 50) && (limit !== 100) && (limit !== 500)) {
+ throw new BadRequest (this.id + ' fetchOrderBook limit must be 0, 5, 10, 20, 50, 100, 500 if specified');
+ }
+ request['depth'] = limit;
+ }
+ const response = await this.publicGetOrderbookMarketPair (this.extend (request, params));
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"376cee43af26deabcd3762ab11a876b6e7a71e82",
+ // "data":{
+ // "bids":[
+ // ["413342637.0000000000","0.165089"],
+ // ["413274576.0000000000","0.03"],
+ // ["413274574.0000000000","0.03"],
+ // ],
+ // "asks":[
+ // ["416979125.0000000000","0.122835"],
+ // ["417248934.0000000000","0.030006"],
+ // ["417458879.0000000000","0.1517"],
+ // ],
+ // "timestamp":"1605841619147"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const timestamp = this.safeValue (data, 'timestamp');
+ return this.parseOrderBook (data, timestamp, 'bids', 'asks', 0, 1);
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // {
+ // "base_id":1,
+ // "quote_id":0,
+ // "last_price":"411119457",
+ // "max_price":"419893173.0000000000",
+ // "min_price":"401292577.0000000000",
+ // "open_price":null,
+ // "base_volume":"10.5915050000",
+ // "quote_volume":"4367495977.4484430060",
+ // "isFrozen":0
+ // }
+ //
+ const timestamp = this.milliseconds ();
+ const baseVolume = this.safeFloat (ticker, 'base_volume');
+ const quoteVolume = this.safeFloat (ticker, 'quote_volume');
+ const open = this.safeFloat (ticker, 'open_price');
+ const last = this.safeFloat (ticker, 'last_price');
+ let change = undefined;
+ let percentage = undefined;
+ let average = undefined;
+ if (last !== undefined && open !== undefined) {
+ change = last - open;
+ average = this.sum (last, open) / 2;
+ if (open > 0) {
+ percentage = change / open * 100;
+ }
+ }
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ const symbol = (market === undefined) ? undefined : market['symbol'];
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'max_price'),
+ 'low': this.safeFloat (ticker, 'min_price'),
+ 'bid': this.safeFloat (ticker, 'bid'),
+ 'bidVolume': undefined,
+ 'ask': this.safeFloat (ticker, 'ask'),
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const response = await this.publicGetTicker (params);
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"fc521161aebe506178b8588cd2adb598eaf1018e",
+ // "data":{
+ // "BTC_VND":{
+ // "base_id":1,
+ // "quote_id":0,
+ // "last_price":"411119457",
+ // "max_price":"419893173.0000000000",
+ // "min_price":"401292577.0000000000",
+ // "open_price":null,
+ // "base_volume":"10.5915050000",
+ // "quote_volume":"4367495977.4484430060",
+ // "isFrozen":0
+ // },
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const ticker = this.safeValue (data, market['id']);
+ return this.parseTicker (ticker, market);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetTicker (params);
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"fc521161aebe506178b8588cd2adb598eaf1018e",
+ // "data":{
+ // "BTC_VND":{
+ // "base_id":1,
+ // "quote_id":0,
+ // "last_price":"411119457",
+ // "max_price":"419893173.0000000000",
+ // "min_price":"401292577.0000000000",
+ // "open_price":null,
+ // "base_volume":"10.5915050000",
+ // "quote_volume":"4367495977.4484430060",
+ // "isFrozen":0
+ // },
+ // }
+ // }
+ //
+ const result = {};
+ const data = this.safeValue (response, 'data');
+ const marketIds = Object.keys (data);
+ for (let i = 0; i < marketIds.length; i++) {
+ const marketId = marketIds[i];
+ const market = this.safeMarket (marketId, undefined, '_');
+ const symbol = market['symbol'];
+ result[symbol] = this.parseTicker (data[marketId], market);
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades
+ //
+ // {
+ // "trade_id":181509285,
+ // "price":"415933022.0000000000",
+ // "base_volume":"0.0022080000",
+ // "quote_volume":"918380.1125760000",
+ // "trade_timestamp":1605842150357,
+ // "type":"buy",
+ // }
+ //
+ // private fetchMyTrades
+ //
+ // {
+ // "trade_type":"sell",
+ // "fee":"0.0610578086",
+ // "id":1483372,
+ // "created_at":1606581578368,
+ // "currency":"usdt",
+ // "coin":"btc",
+ // "price":"17667.1900000000",
+ // "quantity":"0.0017280000",
+ // "amount":"30.5289043200",
+ // }
+ //
+ const timestamp = this.safeInteger2 (trade, 'trade_timestamp', 'created_at');
+ const baseId = this.safeStringUpper (trade, 'coin');
+ const quoteId = this.safeStringUpper (trade, 'currency');
+ let marketId = undefined;
+ if ((baseId !== undefined) && (quoteId !== undefined)) {
+ marketId = baseId + '_' + quoteId;
+ }
+ market = this.safeMarket (marketId, market, '_');
+ const symbol = market['symbol'];
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat2 (trade, 'base_volume', 'quantity');
+ let cost = this.safeFloat2 (trade, 'quote_volume', 'amount');
+ if (cost === undefined) {
+ if ((price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ }
+ const side = this.safeString2 (trade, 'type', 'trade_type');
+ const id = this.safeString2 (trade, 'trade_id', 'id');
+ const feeCost = this.safeFloat (trade, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': market['quote'],
+ };
+ }
+ return {
+ 'info': trade,
+ 'id': id,
+ 'order': undefined,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'type': undefined,
+ 'side': side,
+ 'takerOrMaker': undefined,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market_pair': market['id'],
+ // 'type': 'buy', // 'sell'
+ // 'count': limit, // default 500, max 1000
+ };
+ if (limit !== undefined) {
+ request['count'] = Math.min (1000, limit);
+ }
+ const response = await this.publicGetTradesMarketPair (this.extend (request, params));
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"1f811b533143f739008a3e4ecaaab2ec82ea50d4",
+ // "data":[
+ // {
+ // "trade_id":181509285,
+ // "price":"415933022.0000000000",
+ // "base_volume":"0.0022080000",
+ // "quote_volume":"918380.1125760000",
+ // "trade_timestamp":1605842150357,
+ // "type":"buy",
+ // },
+ // ],
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'type': type, // 'deposit', 'withdraw'
+ // 'start': parseInt (since / 1000),
+ // 'end': this.seconds (),
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency'] = currency['id'];
+ }
+ if (limit !== undefined) {
+ request['limit'] = Math.min (1000, limit);
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ const response = await this.privateGetTransactions (this.extend (request, params));
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"1fdfb0ec85b666871d62fe59d098d01839b05e97",
+ // "data":{
+ // "current_page":1,
+ // "data":[
+ // {
+ // "id":85391,
+ // "user_id":253063,
+ // "transaction_id":"0x885719cee5910ca509a223d208797510e80eb27a2f1d51a71bb4ccb82d538131",
+ // "internal_transaction_id":null,
+ // "temp_transaction_id":"2367",
+ // "currency":"usdt",
+ // "amount":"30.0000000000",
+ // "btc_amount":"0.0000000000",
+ // "usdt_amount":"0.0000000000",
+ // "fee":"0.0000000000",
+ // "tx_cost":"0.0000000000",
+ // "confirmation":0,
+ // "deposit_code":null,
+ // "status":"success",
+ // "bank_name":null,
+ // "foreign_bank_account":null,
+ // "foreign_bank_account_holder":null,
+ // "blockchain_address":"0xd54b84AD27E4c4a8C9E0b2b53701DeFc728f6E44",
+ // "destination_tag":null,
+ // "error_detail":null,
+ // "refunded":"0.0000000000",
+ // "transaction_date":"2020-11-28",
+ // "transaction_timestamp":"1606563143.959",
+ // "created_at":1606563143959,
+ // "updated_at":1606563143959,
+ // "transaction_email_timestamp":0,
+ // "network":null,
+ // "collect_tx_id":null,
+ // "collect_id":null
+ // }
+ // ],
+ // "first_page_url":"http:\/\/api.vcc.exchange\/v3\/transactions?page=1",
+ // "from":1,
+ // "last_page":1,
+ // "last_page_url":"http:\/\/api.vcc.exchange\/v3\/transactions?page=1",
+ // "next_page_url":null,
+ // "path":"http:\/\/api.vcc.exchange\/v3\/transactions",
+ // "per_page":10,
+ // "prev_page_url":null,
+ // "to":1,
+ // "total":1
+ // }
+ // }
+ //
+ let data = this.safeValue (response, 'data', {});
+ data = this.safeValue (data, 'data', []);
+ return this.parseTransactions (data, currency, since, limit);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = { 'type': 'deposit' };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = { 'type': 'withdraw' };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // fetchTransactions, fetchDeposits, fetchWithdrawals
+ //
+ // {
+ // "id":85391,
+ // "user_id":253063,
+ // "transaction_id":"0x885719cee5910ca509a223d208797510e80eb27a2f1d51a71bb4ccb82d538131",
+ // "internal_transaction_id":null,
+ // "temp_transaction_id":"2367",
+ // "currency":"usdt",
+ // "amount":"30.0000000000",
+ // "btc_amount":"0.0000000000",
+ // "usdt_amount":"0.0000000000",
+ // "fee":"0.0000000000",
+ // "tx_cost":"0.0000000000",
+ // "confirmation":0,
+ // "deposit_code":null,
+ // "status":"success",
+ // "bank_name":null,
+ // "foreign_bank_account":null,
+ // "foreign_bank_account_holder":null,
+ // "blockchain_address":"0xd54b84AD27E4c4a8C9E0b2b53701DeFc728f6E44",
+ // "destination_tag":null,
+ // "error_detail":null,
+ // "refunded":"0.0000000000",
+ // "transaction_date":"2020-11-28",
+ // "transaction_timestamp":"1606563143.959",
+ // "created_at":1606563143959,
+ // "updated_at":1606563143959,
+ // "transaction_email_timestamp":0,
+ // "network":null,
+ // "collect_tx_id":null,
+ // "collect_id":null
+ // }
+ //
+ const id = this.safeString (transaction, 'id');
+ const timestamp = this.safeInteger (transaction, 'created_at');
+ const updated = this.safeInteger (transaction, 'updated_at');
+ const currencyId = this.safeString (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ let amount = this.safeFloat (transaction, 'amount');
+ if (amount !== undefined) {
+ amount = Math.abs (amount);
+ }
+ const address = this.safeString (transaction, 'blockchain_address');
+ const txid = this.safeString (transaction, 'transaction_id');
+ const tag = this.safeString (transaction, 'destination_tag');
+ let fee = undefined;
+ const feeCost = this.safeFloat (transaction, 'fee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': code,
+ };
+ }
+ const type = amount > 0 ? 'deposit' : 'withdrawal';
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'address': address,
+ 'addressTo': address,
+ 'addressFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'tagFrom': undefined,
+ 'type': type,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': updated,
+ 'fee': fee,
+ };
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'pending': 'pending',
+ 'error': 'failed',
+ 'success': 'ok',
+ 'cancel': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransactionType (type) {
+ const types = {
+ 'deposit': 'deposit',
+ 'withdraw': 'withdrawal',
+ };
+ return this.safeString (types, type, type);
+ }
+
+ costToPrecision (symbol, cost) {
+ return this.decimalToPrecision (cost, ROUND, this.markets[symbol]['precision']['cost'], this.precisionMode, this.paddingMode);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'coin': market['baseId'],
+ 'currency': market['quoteId'],
+ 'trade_type': side,
+ 'type': type,
+ };
+ if (type === 'ceiling_market') {
+ const ceiling = this.safeValue (params, 'ceiling');
+ if (ceiling !== undefined) {
+ request['ceiling'] = this.costToPrecision (symbol, ceiling);
+ } else if (price !== undefined) {
+ request['ceiling'] = this.costToPrecision (symbol, amount * price);
+ } else {
+ throw new InvalidOrder (this.id + ' createOrder() requires a price argument or a ceiling parameter for ' + type + ' orders');
+ }
+ } else {
+ request['quantity'] = this.amountToPrecision (symbol, amount);
+ }
+ if (type === 'limit') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ const stopPrice = this.safeValue2 (params, 'stop_price', 'stopPrice');
+ if (stopPrice !== undefined) {
+ request['is_stop'] = 1;
+ request['stop_condition'] = (side === 'buy') ? 'le' : 'ge'; // ge = greater than or equal, le = less than or equal
+ request['stop_price'] = this.priceToPrecision (symbol, price);
+ }
+ params = this.omit (params, [ 'stop_price', 'stopPrice' ]);
+ const response = await this.privatePostOrders (this.extend (request, params));
+ //
+ // ceiling_market order
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"213fc0d433f38307f736cae1cbda4cc310469b7a",
+ // "data":{
+ // "coin":"btc",
+ // "currency":"usdt",
+ // "trade_type":"buy",
+ // "type":"ceiling_market",
+ // "ceiling":"30",
+ // "user_id":253063,
+ // "email":"igor.kroitor@gmail.com",
+ // "side":"buy",
+ // "quantity":"0.00172800",
+ // "status":"pending",
+ // "fee":0,
+ // "created_at":1606571333035,
+ // "updated_at":1606571333035,
+ // "instrument_symbol":"BTCUSDT",
+ // "remaining":"0.00172800",
+ // "fee_rate":"0.002",
+ // "id":88214435
+ // }
+ // }
+ //
+ // limit order
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"d9b1159d2bcefa2388be156e32ddc7cc324400ee",
+ // "data":{
+ // "id":41230,
+ // "trade_type":"sell",
+ // "type":"limit",
+ // "quantity":"1",
+ // "price":"14.99",
+ // "currency":"usdt",
+ // "coin":"neo",
+ // "status":"pending",
+ // "is_stop": "1",
+ // "stop_price": "13",
+ // "stop_condition": "ge",
+ // "fee":0,
+ // "created_at":1560244052168,
+ // "updated_at":1560244052168
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'order_id': id,
+ };
+ const response = await this.privatePutOrdersOrderIdCancel (this.extend (request, params));
+ return this.parseOrder (response);
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ const type = this.safeString (params, 'type');
+ const method = (type === undefined) ? 'privatePutOrdersCancelAll' : 'privatePutOrdersCancelByType';
+ const request = {};
+ if (type !== undefined) {
+ request['type'] = type;
+ }
+ await this.loadMarkets ();
+ const response = await this[method] (this.extend (request, params));
+ //
+ // {
+ // "dataVersion":"6d72fb82a9c613c8166581a887e1723ce5a937ff",
+ // "data":{
+ // "data":[
+ // {
+ // "id":410,
+ // "trade_type":"sell",
+ // "currency":"usdt",
+ // "coin":"neo",
+ // "type":"limit",
+ // "quantity":"1.0000000000",
+ // "price":"14.9900000000",
+ // "executed_quantity":"0.0000000000",
+ // "executed_price":"0.0000000000",
+ // "fee":"0.0000000000",
+ // "status":"canceled",
+ // "created_at":1560244052168,
+ // "updated_at":1560244052168,
+ // },
+ // ],
+ // },
+ // }
+ //
+ let data = this.safeValue (response, 'data', {});
+ data = this.safeValue (response, 'data', []);
+ return this.parseOrders (data);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'pending': 'open',
+ 'stopping': 'open',
+ 'executing': 'open',
+ 'executed': 'closed',
+ 'canceled': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // ceiling_market
+ //
+ // {
+ // "coin":"btc",
+ // "currency":"usdt",
+ // "trade_type":"buy",
+ // "type":"ceiling_market",
+ // "ceiling":"30",
+ // "user_id":253063,
+ // "email":"igor.kroitor@gmail.com",
+ // "side":"buy",
+ // "quantity":"0.00172800",
+ // "status":"pending",
+ // "fee":0,
+ // "created_at":1606571333035,
+ // "updated_at":1606571333035,
+ // "instrument_symbol":"BTCUSDT",
+ // "remaining":"0.00172800",
+ // "fee_rate":"0.002",
+ // "id":88214435
+ // }
+ //
+ // limit order
+ //
+ // {
+ // "id":41230,
+ // "trade_type":"sell",
+ // "type":"limit",
+ // "quantity":"1",
+ // "price":"14.99",
+ // "currency":"usdt",
+ // "coin":"neo",
+ // "status":"pending",
+ // "is_stop": "1",
+ // "stop_price": "13",
+ // "stop_condition": "ge",
+ // "fee":0,
+ // "created_at":1560244052168,
+ // "updated_at":1560244052168
+ // }
+ //
+ const created = this.safeValue (order, 'created_at');
+ const updated = this.safeValue (order, 'updated_at');
+ const baseId = this.safeStringUpper (order, 'coin');
+ const quoteId = this.safeStringUpper (order, 'currency');
+ const marketId = baseId + '_' + quoteId;
+ market = this.safeMarket (marketId, market, '_');
+ const symbol = market['symbol'];
+ const amount = this.safeFloat (order, 'quantity');
+ let filled = this.safeFloat (order, 'executed_quantity');
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ let cost = this.safeFloat (order, 'ceiling');
+ const id = this.safeString (order, 'id');
+ let average = undefined;
+ let price = this.safeFloat (order, 'price');
+ // in case of market order
+ if (!price) {
+ price = this.safeFloat (order, 'executed_price');
+ average = price;
+ }
+ let remaining = this.safeFloat (order, 'remaining');
+ if ((filled === undefined) && (amount !== undefined) && (remaining !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ if (filled !== undefined) {
+ if ((amount !== undefined) && (remaining === undefined)) {
+ remaining = Math.max (0, amount - filled);
+ }
+ if ((price !== undefined) && (cost === undefined)) {
+ cost = filled * price;
+ }
+ if ((average === undefined) && (cost !== undefined) && (filled > 0)) {
+ average = cost / filled;
+ }
+ }
+ const type = this.safeString (order, 'type');
+ const side = this.safeString (order, 'trade_type');
+ const fee = {
+ 'currency': market['quote'],
+ 'cost': this.safeFloat (order, 'fee'),
+ 'rate': this.safeFloat (order, 'fee_rate'),
+ };
+ let lastTradeTimestamp = undefined;
+ if (updated !== created) {
+ lastTradeTimestamp = updated;
+ }
+ const stopPrice = this.safeFloat (order, 'stopPrice');
+ return {
+ 'id': id,
+ 'clientOrderId': id,
+ 'timestamp': created,
+ 'datetime': this.iso8601 (created),
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'status': status,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': stopPrice,
+ 'average': average,
+ 'amount': amount,
+ 'cost': cost,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'fee': fee,
+ 'trades': undefined,
+ 'info': order,
+ };
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'order_id': id,
+ };
+ const response = await this.privateGetOrdersOrderId (this.extend (request, params));
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"57448aa1fb8f227254e8e2e925b3ade8e1e5bbef",
+ // "data":{
+ // "id":88265741,
+ // "user_id":253063,
+ // "email":"igor.kroitor@gmail.com",
+ // "updated_at":1606581578141,
+ // "created_at":1606581578141,
+ // "coin":"btc",
+ // "currency":"usdt",
+ // "type":"market",
+ // "trade_type":"sell",
+ // "executed_price":"17667.1900000000",
+ // "price":null,
+ // "executed_quantity":"0.0017280000",
+ // "quantity":"0.0017280000",
+ // "fee":"0.0610578086",
+ // "status":"executed",
+ // "is_stop":0,
+ // "stop_condition":null,
+ // "stop_price":null,
+ // "ceiling":null
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data);
+ }
+
+ async fetchOrdersWithMethod (method, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'page': 1,
+ // 'limit': limit, // max 1000
+ // 'start_date': since,
+ // 'end_date': this.milliseconds (),
+ // 'currency': market['quoteId'],
+ // 'coin': market['baseId'],
+ // 'trade_type': 'buy', // or 'sell'
+ // 'hide_canceled': 0, // 1 to exclude canceled orders
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['coin'] = market['baseId'];
+ request['currency'] = market['quoteId'];
+ }
+ if (since !== undefined) {
+ request['start_date'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = Math.min (1000, limit); // max 1000
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"89aa11497f23fdd34cf9de9c55acfad863c78780",
+ // "data":{
+ // "current_page":1,
+ // "data":[
+ // {
+ // "id":88489678,
+ // "email":"igor.kroitor@gmail.com",
+ // "updated_at":1606628593567,
+ // "created_at":1606628593567,
+ // "coin":"btc",
+ // "currency":"usdt",
+ // "type":"limit",
+ // "trade_type":"buy",
+ // "executed_price":"0.0000000000",
+ // "price":"10000.0000000000",
+ // "executed_quantity":"0.0000000000",
+ // "quantity":"0.0010000000",
+ // "fee":"0.0000000000",
+ // "status":"pending",
+ // "is_stop":0,
+ // "stop_condition":null,
+ // "stop_price":null,
+ // "ceiling":null,
+ // },
+ // ],
+ // "first_page_url":"http:\/\/api.vcc.exchange\/v3\/orders\/open?page=1",
+ // "from":1,
+ // "last_page":1,
+ // "last_page_url":"http:\/\/api.vcc.exchange\/v3\/orders\/open?page=1",
+ // "next_page_url":null,
+ // "path":"http:\/\/api.vcc.exchange\/v3\/orders\/open",
+ // "per_page":10,
+ // "prev_page_url":null,
+ // "to":1,
+ // "total":1,
+ // },
+ // }
+ //
+ let data = this.safeValue (response, 'data', {});
+ data = this.safeValue (data, 'data', []);
+ return this.parseOrders (data, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchOrdersWithMethod ('privateGetOrdersOpen', symbol, since, limit, params);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchOrdersWithMethod ('privateGetOrders', symbol, since, limit, params);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'page': 1,
+ // 'limit': limit, // max 1000
+ // 'start_date': since,
+ // 'end_date': this.milliseconds (),
+ // 'currency': market['quoteId'],
+ // 'coin': market['baseId'],
+ // 'trade_type': 'buy', // or 'sell'
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['coin'] = market['baseId'];
+ request['currency'] = market['quoteId'];
+ }
+ if (since !== undefined) {
+ request['start_date'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = Math.min (1000, limit); // max 1000
+ }
+ const response = await this.privateGetOrdersTrades (this.extend (request, params));
+ //
+ // {
+ // "message":null,
+ // "dataVersion":"eb890af684cf84e20044e9a9771b96302e7b8dec",
+ // "data":{
+ // "current_page":1,
+ // "data":[
+ // {
+ // "trade_type":"sell",
+ // "fee":"0.0610578086",
+ // "id":1483372,
+ // "created_at":1606581578368,
+ // "currency":"usdt",
+ // "coin":"btc",
+ // "price":"17667.1900000000",
+ // "quantity":"0.0017280000",
+ // "amount":"30.5289043200",
+ // },
+ // ],
+ // "first_page_url":"http:\/\/api.vcc.exchange\/v3\/orders\/trades?page=1",
+ // "from":1,
+ // "last_page":1,
+ // "last_page_url":"http:\/\/api.vcc.exchange\/v3\/orders\/trades?page=1",
+ // "next_page_url":null,
+ // "path":"http:\/\/api.vcc.exchange\/v3\/orders\/trades",
+ // "per_page":10,
+ // "prev_page_url":null,
+ // "to":2,
+ // "total":2,
+ // },
+ // }
+ //
+ let data = this.safeValue (response, 'data', {});
+ data = this.safeValue (data, 'data', []);
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privateGetDepositAddress (this.extend (request, params));
+ //
+ // {
+ // "dataVersion":"6d72fb82a9c613c8166581a887e1723ce5a937ff",
+ // "data":{
+ // "status": "REQUESTED",
+ // "blockchain_address": "",
+ // "currency": "btc"
+ // }
+ // }
+ //
+ // {
+ // "dataVersion":"6d72fb82a9c613c8166581a887e1723ce5a937ff",
+ // "data":{
+ // "status": "PROVISIONED",
+ // "blockchain_address": "rPVMhWBsfF9iMXYj3aAzJVkPDTFNSyWdKy",
+ // "blockchain_tag": "920396135",
+ // "currency": "xrp"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const status = this.safeString (data, 'status');
+ if (status === 'REQUESTED') {
+ throw new AddressPending (this.id + ' is generating ' + code + ' deposit address, call fetchDepositAddress one more time later to retrieve the generated address');
+ }
+ const address = this.safeString (data, 'blockchain_address');
+ this.checkAddress (address);
+ const tag = this.safeString (data, 'blockchain_tag');
+ const currencyId = this.safeString (data, 'currency');
+ return {
+ 'currency': this.safeCurrencyCode (currencyId),
+ 'address': address,
+ 'tag': tag,
+ 'info': data,
+ };
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let url = this.version + '/' + this.implodeParams (path, params);
+ const query = this.omit (params, this.extractParams (path));
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ if (api === 'private') {
+ this.checkRequiredCredentials ();
+ const timestamp = this.milliseconds ().toString ();
+ if (method !== 'GET') {
+ body = this.json (query);
+ }
+ const auth = method + ' ' + url;
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256');
+ headers = {
+ 'Authorization': 'Bearer ' + this.apiKey,
+ 'Content-Type': 'application/json',
+ 'timestamp': timestamp,
+ 'signature': signature,
+ };
+ }
+ url = this.urls['api'][api] + '/' + url;
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return;
+ }
+ //
+ // {"message":"Insufficient balance."}
+ // {"message":"Unauthenticated."} // wrong api key
+ // {"message":"The given data was invalid.","errors":{"signature":["HMAC signature is invalid"]}}
+ // {"code":504,"message":"Gateway Timeout","description":""}
+ // {"code":429,"message":"Too many requests","description":"Too many requests"}
+ //
+ const message = this.safeString (response, 'message');
+ if (message !== undefined) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], body, feedback);
+ throw new ExchangeError (feedback);
+ }
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7,"./base/functions/number":13}],173:[function(require,module,exports){
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ArgumentsRequired, AuthenticationError, InsufficientFunds, InvalidOrder, AccountSuspended, ExchangeError, DuplicateOrderId, OrderNotFound, BadSymbol, ExchangeNotAvailable, BadRequest } = require ('./base/errors');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class wavesexchange extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'wavesexchange',
+ 'name': 'Waves.Exchange',
+ 'countries': ['CH'], // Switzerland
+ 'rateLimit': 500,
+ 'certified': true,
+ 'pro': false,
+ 'has': {
+ 'cancelOrder': true,
+ 'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchDepositAddress': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '5m': '5m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '2h': '2h',
+ '3h': '3h',
+ '4h': '4h',
+ '6h': '6h',
+ '12h': '12h',
+ '1d': '1d',
+ '1w': '1w',
+ '1M': '1M',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/84547058-5fb27d80-ad0b-11ea-8711-78ac8b3c7f31.jpg',
+ 'api': {
+ 'matcher': 'http://matcher.waves.exchange',
+ 'node': 'https://nodes.waves.exchange',
+ 'public': 'https://api.wavesplatform.com/v0',
+ 'private': 'https://api.waves.exchange/v1',
+ 'forward': 'https://waves.exchange/api/v1/forward/matcher',
+ 'market': 'https://marketdata.wavesplatform.com/api/v1',
+ },
+ 'doc': 'https://docs.waves.exchange',
+ 'www': 'https://waves.exchange',
+ },
+ 'api': {
+ 'matcher': {
+ 'get': [
+ 'matcher',
+ 'matcher/settings',
+ 'matcher/settings/rates',
+ 'matcher/balance/reserved/{publicKey}',
+ 'matcher/debug/allSnashotOffsets',
+ 'matcher/debug/currentOffset',
+ 'matcher/debug/lastOffset',
+ 'matcher/debug/oldestSnapshotOffset',
+ 'matcher/orderbook',
+ 'matcher/orderbook/{amountAsset}/{priceAsset}',
+ 'matcher/orderbook/{baseId}/{quoteId}/publicKey/{publicKey}',
+ 'matcher/orderbook/{baseId}/{quoteId}/{orderId}',
+ 'matcher/orderbook/{baseId}/{quoteId}/info',
+ 'matcher/orderbook/{baseId}/{quoteId}/status',
+ 'matcher/orderbook/{baseId}/{quoteId}/tradeableBalance/{address}',
+ 'matcher/orderbook/{publicKey}',
+ 'matcher/orderbook/{publicKey}/{orderId}',
+ 'matcher/orders/{address}',
+ 'matcher/orders/{address}/{orderId}',
+ 'matcher/transactions/{orderId}',
+ ],
+ 'post': [
+ 'matcher/orderbook',
+ 'matcher/orderbook/market',
+ 'matcher/orderbook/cancel',
+ 'matcher/orderbook/{baseId}/{quoteId}/cancel',
+ 'matcher/debug/saveSnapshots',
+ 'matcher/orders/{address}/cancel',
+ 'matcher/orders/cancel/{orderId}',
+ ],
+ 'delete': [
+ 'matcher/orderbook/{baseId}/{quoteId}',
+ 'matcher/settings/rates/{assetId}',
+ ],
+ 'put': [
+ 'matcher/settings/rates/{assetId}',
+ ],
+ },
+ 'node': {
+ 'get': [
+ 'addresses',
+ 'addresses/balance/{address}',
+ 'addresses/balance/{address}/{confirmations}',
+ 'addresses/balance/details/{address}',
+ 'addresses/data/{address}',
+ 'addresses/data/{address}/{key}',
+ 'addresses/effectiveBalance/{address}',
+ 'addresses/effectiveBalance/{address}/{confirmations}',
+ 'addresses/publicKey/{publicKey}',
+ 'addresses/scriptInfo/{address}',
+ 'addresses/scriptInfo/{address}/meta',
+ 'addresses/seed/{address}',
+ 'addresses/seq/{from}/{to}',
+ 'addresses/validate/{address}',
+ 'alias/by-address/{address}',
+ 'alias/by-alias/{alias}',
+ 'assets/{assetId}/distribution/{height}/{limit}',
+ 'assets/balance/{address}',
+ 'assets/balance/{address}/{assetId}',
+ 'assets/details/{assetId}',
+ 'assets/nft/{address}/limit/{limit}',
+ 'blockchain/rewards',
+ 'blockchain/rewards/height',
+ 'blocks/address/{address}/{from}/{to}/',
+ 'blocks/at/{height}',
+ 'blocks/delay/{signature}/{blockNum}',
+ 'blocks/first',
+ 'blocks/headers/last',
+ 'blocks/headers/seq/{from}/{to}',
+ 'blocks/height',
+ 'blocks/height/{signature}',
+ 'blocks/last',
+ 'blocks/seq/{from}/{to}',
+ 'blocks/signature/{signature}',
+ 'consensus/algo',
+ 'consensus/basetarget',
+ 'consensus/basetarget/{blockId}',
+ 'consensus/{generatingbalance}/address',
+ 'consensus/generationsignature',
+ 'consensus/generationsignature/{blockId}',
+ 'debug/balances/history/{address}',
+ 'debug/blocks/{howMany}',
+ 'debug/configInfo',
+ 'debug/historyInfo',
+ 'debug/info',
+ 'debug/minerInfo',
+ 'debug/portfolios/{address}',
+ 'debug/state',
+ 'debug/stateChanges/address/{address}',
+ 'debug/stateChanges/info/{id}',
+ 'debug/stateWaves/{height}',
+ 'leasing/active/{address}',
+ 'node/state',
+ 'node/version',
+ 'peers/all',
+ 'peers/blacklisted',
+ 'peers/connected',
+ 'peers/suspended',
+ 'transactions/address/{address}/limit/{limit}',
+ 'transactions/info/{id}',
+ 'transactions/status',
+ 'transactions/unconfirmed',
+ 'transactions/unconfirmed/info/{id}',
+ 'transactions/unconfirmed/size',
+ 'utils/seed',
+ 'utils/seed/{length}',
+ 'utils/time',
+ 'wallet/seed',
+ ],
+ 'post': [
+ 'addresses',
+ 'addresses/data/{address}',
+ 'addresses/sign/{address}',
+ 'addresses/signText/{address}',
+ 'addresses/verify/{address}',
+ 'addresses/verifyText/{address}',
+ 'debug/blacklist',
+ 'debug/print',
+ 'debug/rollback',
+ 'debug/validate',
+ 'node/stop',
+ 'peers/clearblacklist',
+ 'peers/connect',
+ 'transactions/broadcast',
+ 'transactions/calculateFee',
+ 'tranasctions/sign',
+ 'transactions/sign/{signerAddress}',
+ 'tranasctions/status',
+ 'utils/hash/fast',
+ 'utils/hash/secure',
+ 'utils/script/compileCode',
+ 'utils/script/compileWithImports',
+ 'utils/script/decompile',
+ 'utils/script/estimate',
+ 'utils/sign/{privateKey}',
+ 'utils/transactionsSerialize',
+ ],
+ 'delete': [
+ 'addresses/{address}',
+ 'debug/rollback-to/{signature}',
+ ],
+ },
+ 'public': {
+ 'get': [
+ 'pairs',
+ 'candles/{baseId}/{quoteId}',
+ 'transactions/exchange',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'deposit/addresses/{code}',
+ 'deposit/currencies',
+ 'withdraw/currencies',
+ 'withdraw/addresses/{currency}/{address}',
+ ],
+ 'post': [
+ 'oauth2/token',
+ ],
+ },
+ 'forward': {
+ 'get': [
+ 'matcher/orders/{address}', // can't get the orders endpoint to work with the matcher api
+ 'matcher/orders/{address}/{orderId}',
+ ],
+ 'post': [
+ 'matcher/orders/{wavesAddress}/cancel',
+ ],
+ },
+ 'market': {
+ 'get': [
+ 'tickers',
+ ],
+ },
+ },
+ 'options': {
+ 'allowedCandles': 1440,
+ 'accessToken': undefined,
+ 'matcherPublicKey': undefined,
+ 'quotes': undefined,
+ 'createOrderDefaultExpiry': 2419200000, // 60 * 60 * 24 * 28 * 1000
+ 'wavesAddress': undefined,
+ 'withdrawFeeUSDN': 7420,
+ 'withdrawFeeWAVES': 100000,
+ 'wavesPrecision': 8,
+ },
+ 'requiresEddsa': true,
+ 'exceptions': {
+ '3147270': InsufficientFunds, // https://github.com/wavesplatform/matcher/wiki/List-of-all-errors
+ '112': InsufficientFunds,
+ '4': ExchangeError,
+ '13': ExchangeNotAvailable,
+ '14': ExchangeNotAvailable,
+ '3145733': AccountSuspended,
+ '3148040': DuplicateOrderId,
+ '3148801': AuthenticationError,
+ '9440512': AuthenticationError,
+ '9440771': BadSymbol,
+ '9441026': InvalidOrder,
+ '9441282': InvalidOrder,
+ '9441286': InvalidOrder,
+ '9441295': InvalidOrder,
+ '9441540': InvalidOrder,
+ '9441542': InvalidOrder,
+ '106954752': AuthenticationError,
+ '106954769': AuthenticationError,
+ '106957828': AuthenticationError,
+ '106960131': AuthenticationError,
+ '106981137': AuthenticationError,
+ '9437193': OrderNotFound,
+ '1048577': BadRequest,
+ '1051904': AuthenticationError,
+ },
+ });
+ }
+
+ async getQuotes () {
+ let quotes = this.safeValue (this.options, 'quotes');
+ if (quotes) {
+ return quotes;
+ } else {
+ // currencies can have any name because you can create you own token
+ // as a result someone can create a fake token called BTC
+ // we use this mapping to determine the real tokens
+ // https://docs.waves.exchange/en/waves-matcher/matcher-api#asset-pair
+ const response = await this.matcherGetMatcherSettings ();
+ // {
+ // "orderVersions": [
+ // 1,
+ // 2,
+ // 3
+ // ],
+ // "success": true,
+ // "matcherPublicKey": "9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
+ // "orderFee": {
+ // "dynamic": {
+ // "baseFee": 300000,
+ // "rates": {
+ // "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ": 1.22639597,
+ // "62LyMjcr2DtiyF5yVXFhoQ2q414VPPJXjsNYp72SuDCH": 0.00989643,
+ // "HZk1mbfuJpmxU1Fs4AX5MWLVYtctsNcg6e2C6VKqK8zk": 0.0395674,
+ // "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS": 0.00018814,
+ // "4LHHvYGNKJUg5hj65aGD5vgScvCBmLpdRFtjokvCjSL8": 26.19721262,
+ // "474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu": 0.00752978,
+ // "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p": 1.84575,
+ // "B3uGHFRpSUuGEDWjqB9LWWxafQj8VTvpMucEyoxzws5H": 0.02330273,
+ // "zMFqXuoyrn5w17PFurTqxB7GsS71fp9dfk6XFwxbPCy": 0.00721412,
+ // "5WvPKSJXzVE2orvbkJ8wsQmmQKqTv9sGBPksV4adViw3": 0.02659103,
+ // "WAVES": 1,
+ // "BrjUWjndUanm5VsJkbUip8VRYy6LWJePtxya3FNv4TQa": 0.03433583
+ // }
+ // }
+ // },
+ // "networkByte": 87,
+ // "matcherVersion": "2.1.3.5",
+ // "status": "SimpleResponse",
+ // "priceAssets": [
+ // "Ft8X1v1LTa1ABafufpaCWyVj8KkaxUWE6xBhW6sNFJck",
+ // "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p",
+ // "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ",
+ // "Gtb1WRznfchDnTh37ezoDTJ4wcoKaRsKqKjJjy7nm2zU",
+ // "2mX5DzVKWrAJw8iwdJnV2qtoeVG9h5nTDpTqC1wb1WEN",
+ // "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS",
+ // "WAVES",
+ // "474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu",
+ // "zMFqXuoyrn5w17PFurTqxB7GsS71fp9dfk6XFwxbPCy",
+ // "62LyMjcr2DtiyF5yVXFhoQ2q414VPPJXjsNYp72SuDCH",
+ // "HZk1mbfuJpmxU1Fs4AX5MWLVYtctsNcg6e2C6VKqK8zk",
+ // "B3uGHFRpSUuGEDWjqB9LWWxafQj8VTvpMucEyoxzws5H",
+ // "5WvPKSJXzVE2orvbkJ8wsQmmQKqTv9sGBPksV4adViw3",
+ // "BrjUWjndUanm5VsJkbUip8VRYy6LWJePtxya3FNv4TQa",
+ // "4LHHvYGNKJUg5hj65aGD5vgScvCBmLpdRFtjokvCjSL8"
+ // ]
+ // }
+ quotes = {};
+ const priceAssets = this.safeValue (response, 'priceAssets');
+ for (let i = 0; i < priceAssets.length; i++) {
+ quotes[priceAssets[i]] = true;
+ }
+ this.options['quotes'] = quotes;
+ return quotes;
+ }
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.marketGetTickers ();
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const entry = response[i];
+ const baseId = this.safeString (entry, 'amountAssetID');
+ const quoteId = this.safeString (entry, 'priceAssetID');
+ const id = baseId + '/' + quoteId;
+ const marketId = this.safeString (entry, 'symbol');
+ const [ base, quote ] = marketId.split ('/');
+ const symbol = this.safeCurrencyCode (base) + '/' + this.safeCurrencyCode (quote);
+ const precision = {
+ 'amount': this.safeInteger (entry, 'amountAssetDecimals'),
+ 'price': this.safeInteger (entry, 'priceAssetDecimals'),
+ };
+ result.push ({
+ 'symbol': symbol,
+ 'id': id,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'info': entry,
+ 'precision': precision,
+ });
+ }
+ return result;
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = this.extend ({
+ 'amountAsset': market['baseId'],
+ 'priceAsset': market['quoteId'],
+ }, params);
+ const response = await this.matcherGetMatcherOrderbookAmountAssetPriceAsset (request);
+ const timestamp = this.safeInteger (response, 'timestamp');
+ const bids = this.parseOrderBookSide (this.safeValue (response, 'bids'), market, limit);
+ const asks = this.parseOrderBookSide (this.safeValue (response, 'asks'), market, limit);
+ return {
+ 'bids': bids,
+ 'asks': asks,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'nonce': undefined,
+ };
+ }
+
+ parseOrderBookSide (bookSide, market = undefined, limit = undefined) {
+ const precision = market['precision'];
+ const wavesPrecision = this.safeInteger (this.options, 'wavesPrecision', 8);
+ const amountPrecision = Math.pow (10, precision['amount']);
+ const difference = precision['amount'] - precision['price'];
+ const pricePrecision = Math.pow (10, wavesPrecision - difference);
+ const result = [];
+ for (let i = 0; i < bookSide.length; i++) {
+ const entry = bookSide[i];
+ const price = this.safeInteger (entry, 'price', 0) / pricePrecision;
+ const amount = this.safeInteger (entry, 'amount', 0) / amountPrecision;
+ if ((limit !== undefined) && (i > limit)) {
+ break;
+ }
+ result.push ([price, amount]);
+ }
+ return result;
+ }
+
+ checkRequiredKeys () {
+ if (this.apiKey === undefined) {
+ throw new AuthenticationError (this.id + ' requires apiKey credential');
+ }
+ if (this.secret === undefined) {
+ throw new AuthenticationError (this.id + ' requires secret credential');
+ }
+ let apiKeyBytes = undefined;
+ let secretKeyBytes = undefined;
+ try {
+ apiKeyBytes = this.base58ToBinary (this.apiKey);
+ } catch (e) {
+ throw new AuthenticationError (this.id + ' apiKey must be a base58 encoded public key');
+ }
+ try {
+ secretKeyBytes = this.base58ToBinary (this.secret);
+ } catch (e) {
+ throw new AuthenticationError (this.id + ' secret must be a base58 encoded private key');
+ }
+ const hexApiKeyBytes = this.binaryToBase16 (apiKeyBytes);
+ const hexSecretKeyBytes = this.binaryToBase16 (secretKeyBytes);
+ if (hexApiKeyBytes.length !== 64) {
+ throw new AuthenticationError (this.id + ' apiKey must be a base58 encoded public key');
+ }
+ if (hexSecretKeyBytes.length !== 64) {
+ throw new AuthenticationError (this.id + ' secret must be a base58 encoded private key');
+ }
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const query = this.omit (params, this.extractParams (path));
+ const isCancelOrder = path === 'matcher/orders/{wavesAddress}/cancel';
+ path = this.implodeParams (path, params);
+ let url = this.urls['api'][api] + '/' + path;
+ let queryString = this.urlencode (query);
+ if ((api === 'private') || (api === 'forward')) {
+ headers = {
+ 'Accept': 'application/json',
+ };
+ const accessToken = this.safeString (this.options, 'accessToken');
+ if (accessToken) {
+ headers['Authorization'] = 'Bearer ' + accessToken;
+ }
+ if (method === 'POST') {
+ headers['content-type'] = 'application/json';
+ } else {
+ headers['content-type'] = 'application/x-www-form-urlencoded';
+ }
+ if (isCancelOrder) {
+ body = this.json ([query['orderId']]);
+ queryString = '';
+ }
+ if (queryString.length > 0) {
+ url += '?' + queryString;
+ }
+ } else if (api === 'matcher') {
+ if (method === 'POST') {
+ headers = {
+ 'content-type': 'application/json',
+ };
+ body = this.json (query);
+ } else {
+ headers = query;
+ }
+ } else {
+ if (method === 'POST') {
+ headers = {
+ 'content-type': 'application/json',
+ };
+ body = this.json (query);
+ } else {
+ headers = {
+ 'content-type': 'application/x-www-form-urlencoded',
+ };
+ if (queryString.length > 0) {
+ url += '?' + queryString;
+ }
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ async getAccessToken () {
+ if (!this.safeString (this.options, 'accessToken')) {
+ const prefix = 'ffffff01';
+ const expiresDelta = 60 * 60 * 24 * 7;
+ let seconds = this.sum (this.seconds (), expiresDelta);
+ seconds = seconds.toString ();
+ const clientId = 'waves.exchange';
+ const message = 'W:' + clientId + ':' + seconds;
+ const messageHex = this.binaryToBase16 (this.stringToBinary (this.encode (message)));
+ const payload = prefix + messageHex;
+ const hexKey = this.binaryToBase16 (this.base58ToBinary (this.secret));
+ const signature = this.eddsa (payload, hexKey, 'ed25519');
+ const request = {
+ 'grant_type': 'password',
+ 'scope': 'general',
+ 'username': this.apiKey,
+ 'password': seconds + ':' + signature,
+ 'client_id': clientId,
+ };
+ const response = await this.privatePostOauth2Token (request);
+ // { access_token: 'eyJhbGciOXJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaWciOiJiaTZiMVhMQlo0M1Q4QmRTSlVSejJBZGlQdVlpaFZQYVhhVjc4ZGVIOEpTM3M3NUdSeEU1VkZVOE5LRUI0UXViNkFHaUhpVFpuZ3pzcnhXdExUclRvZTgiLCJhIjoiM1A4VnpMU2EyM0VXNUNWY2tIYlY3ZDVCb043NWZGMWhoRkgiLCJuYiI6IlciLCJ1c2VyX25hbWUiOiJBSFhuOG5CQTRTZkxRRjdoTFFpU24xNmt4eWVoaml6QkdXMVRkcm1TWjFnRiIsInNjb3BlIjpbImdlbmVyYWwiXSwibHQiOjYwNDc5OSwicGsiOiJBSFhuOG5CQTRTZkxRRjdoTFFpU24xNmt4eWVoaml6QkdXMVRkcm1TWjFnRiIsImV4cCI6MTU5MTk3NTA1NywiZXhwMCI6MTU5MTk3NTA1NywianRpIjoiN2JhOTUxMTMtOGI2MS00NjEzLTlkZmYtNTEwYTc0NjlkOWI5IiwiY2lkIjoid2F2ZXMuZXhjaGFuZ2UifQ.B-XwexBnUAzbWknVN68RKT0ZP5w6Qk1SKJ8usL3OIwDEzCUUX9PjW-5TQHmiCRcA4oft8lqXEiCwEoNfsblCo_jTpRo518a1vZkIbHQk0-13Dm1K5ewGxfxAwBk0g49odcbKdjl64TN1yM_PO1VtLVuiTeZP-XF-S42Uj-7fcO-r7AulyQLuTE0uo-Qdep8HDCk47rduZwtJOmhFbCCnSgnLYvKWy3CVTeldsR77qxUY-vy8q9McqeP7Id-_MWnsob8vWXpkeJxaEsw1Fke1dxApJaJam09VU8EB3ZJWpkT7V8PdafIrQGeexx3jhKKxo7rRb4hDV8kfpVoCgkvFan',
+ // token_type: 'bearer',
+ // refresh_token: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzaWciOiJiaTZiMVhMQlo0M1Q4QmRTSlVSejJBZGlQdVlpaFZQYVhhVjc4ZGVIOEpTM3M3NUdSeEU1VkZVOE5LRUI0UXViNkFHaUhpVFpuZ3pzcnhXdExUclRvZTgiLCJhIjoiM1A4VnpMU2EyM0VXNUNWY2tIYlY3ZDVCb043NWZGMWhoRkgiLCJuYiI6IlciLCJ1c2VyX25hbWUiOiJBSFhuOG5CQTRTZkxRRjdoTFFpU24xNmt4eWVoaml6QkdXMVRkcm1TWjFnRiIsInNjb3BlIjpbImdlbmVyYWwiXSwiYXRpIjoiN2JhOTUxMTMtOGI2MS00NjEzLTlkZmYtNTEwYTc0NjlkXWI5IiwibHQiOjYwNDc5OSwicGsiOiJBSFhuOG5CQTRTZkxRRjdoTFFpU24xNmt4eWVoaml6QkdXMVRkcm1TWjFnRiIsImV4cCI6MTU5Mzk2MjI1OCwiZXhwMCI6MTU5MTk3NTA1NywianRpIjoiM2MzZWRlMTktNjI5My00MTNlLWJmMWUtZTRlZDZlYzUzZTgzIiwiY2lkIjoid2F2ZXMuZXhjaGFuZ2UifQ.gD1Qj0jfqayfZpBvNY0t3ccMyK5hdbT7dY-_5L6LxwV0Knan4ndEtvygxlTOczmJUKtnA4T1r5GBFgNMZTvtViKZIbqZNysEg2OY8UxwDaF4VPeGJLg_QXEnn8wBeBQdyMafh9UQdwD2ci7x-saM4tOAGmncAygfTDxy80201gwDhfAkAGerb9kL00oWzSJScldxu--pNLDBUEHZt52MSEel10HGrzvZkkvvSh67vcQo5TOGb5KG6nh65UdJCwr41AVz4fbQPP-N2Nkxqy0TE_bqVzZxExXgvcS8TS0Z82T3ijJa_ct7B9wblpylBnvmyj3VycUzufD6uy8MUGq32D',
+ // expires_in: 604798,
+ // scope: 'general' }
+ this.options['accessToken'] = this.safeString (response, 'access_token');
+ return this.options['accessToken'];
+ }
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // {
+ // "__type":"pair",
+ // "data":{
+ // "firstPrice":0.00012512,
+ // "lastPrice":0.00012441,
+ // "low":0.00012167,
+ // "high":0.00012768,
+ // "weightedAveragePrice":0.000124710697407246,
+ // "volume":209554.26356614,
+ // "quoteVolume":26.1336583539951,
+ // "volumeWaves":209554.26356614,
+ // "txsCount":6655
+ // },
+ // "amountAsset":"WAVES",
+ // "priceAsset":"8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS"
+ // }
+ //
+ const timestamp = undefined;
+ const baseId = this.safeString (ticker, 'amountAsset');
+ const quoteId = this.safeString (ticker, 'priceAsset');
+ let symbol = undefined;
+ if ((baseId !== undefined) && (quoteId !== undefined)) {
+ const marketId = baseId + '/' + quoteId;
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ const data = this.safeValue (ticker, 'data', {});
+ const last = this.safeFloat (data, 'lastPrice');
+ const low = this.safeFloat (data, 'low');
+ const high = this.safeFloat (data, 'high');
+ const vwap = this.safeFloat (data, 'weightedAveragePrice');
+ const baseVolume = this.safeFloat (data, 'volume');
+ const quoteVolume = this.safeFloat (data, 'quoteVolume');
+ const open = this.safeValue (data, 'firstPrice');
+ let change = undefined;
+ let average = undefined;
+ let percentage = undefined;
+ if (last !== undefined && open !== undefined) {
+ change = last - open;
+ average = this.sum (last, open) / 2;
+ if (open > 0) {
+ percentage = change / open * 100;
+ }
+ }
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': high,
+ 'low': low,
+ 'bid': undefined,
+ 'bidVolume': undefined,
+ 'ask': undefined,
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'pairs': market['id'],
+ };
+ const response = await this.publicGetPairs (this.extend (request, params));
+ //
+ // {
+ // "__type":"list",
+ // "data":[
+ // {
+ // "__type":"pair",
+ // "data":{
+ // "firstPrice":0.00012512,
+ // "lastPrice":0.00012441,
+ // "low":0.00012167,
+ // "high":0.00012768,
+ // "weightedAveragePrice":0.000124710697407246,
+ // "volume":209554.26356614,
+ // "quoteVolume":26.1336583539951,
+ // "volumeWaves":209554.26356614,
+ // "txsCount":6655
+ // },
+ // "amountAsset":"WAVES",
+ // "priceAsset":"8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS"
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const ticker = this.safeValue (data, 0, {});
+ return this.parseTicker (ticker, market);
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'baseId': market['baseId'],
+ 'quoteId': market['quoteId'],
+ 'interval': this.timeframes[timeframe],
+ };
+ if (since !== undefined) {
+ request['timeStart'] = since.toString ();
+ } else {
+ const allowedCandles = this.safeInteger (this.options, 'allowedCandles', 1440);
+ const timeframeUnix = this.parseTimeframe (timeframe) * 1000;
+ const currentTime = Math.floor (this.milliseconds () / timeframeUnix) * timeframeUnix;
+ const delta = (allowedCandles - 1) * timeframeUnix;
+ const timeStart = currentTime - delta;
+ request['timeStart'] = timeStart.toString ();
+ }
+ const response = await this.publicGetCandlesBaseIdQuoteId (this.extend (request, params));
+ //
+ // {
+ // "__type": "list",
+ // "data": [
+ // {
+ // "__type": "candle",
+ // "data": {
+ // "time": "2020-06-09T14:47:00.000Z",
+ // "open": 0.0250385,
+ // "close": 0.0250385,
+ // "high": 0.0250385,
+ // "low": 0.0250385,
+ // "volume": 0.01033012,
+ // "quoteVolume": 0.00025865,
+ // "weightedAveragePrice": 0.0250385,
+ // "maxHeight": 2099399,
+ // "txsCount": 5,
+ // "timeClose": "2020-06-09T14:47:59.999Z"
+ // }
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = this.parseOHLCVs (data, market, timeframe, since, limit);
+ let lastClose = undefined;
+ const length = result.length;
+ for (let i = 0; i < result.length; i++) {
+ const j = length - i - 1;
+ const entry = result[j];
+ const open = entry[1];
+ if (open === undefined) {
+ entry[1] = lastClose;
+ entry[2] = lastClose;
+ entry[3] = lastClose;
+ entry[4] = lastClose;
+ result[j] = entry;
+ }
+ lastClose = entry[4];
+ }
+ return result;
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // __type: 'candle',
+ // data: {
+ // time: '2020-06-05T20:46:00.000Z',
+ // open: 240.573975,
+ // close: 240.573975,
+ // high: 240.573975,
+ // low: 240.573975,
+ // volume: 0.01278413,
+ // quoteVolume: 3.075528,
+ // weightedAveragePrice: 240.573975,
+ // maxHeight: 2093895,
+ // txsCount: 5,
+ // timeClose: '2020-06-05T20:46:59.999Z'
+ // }
+ // }
+ //
+ const data = this.safeValue (ohlcv, 'data', {});
+ return [
+ this.parse8601 (this.safeString (data, 'time')),
+ this.safeFloat (data, 'open'),
+ this.safeFloat (data, 'high'),
+ this.safeFloat (data, 'low'),
+ this.safeFloat (data, 'close'),
+ this.safeFloat (data, 'volume', 0),
+ ];
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.getAccessToken ();
+ const supportedCurrencies = await this.privateGetDepositCurrencies ();
+ const currencies = {};
+ const items = this.safeValue (supportedCurrencies, 'items', []);
+ for (let i = 0; i < items.length; i++) {
+ const entry = items[i];
+ const currencyCode = this.safeString (entry, 'id');
+ currencies[currencyCode] = true;
+ }
+ if (!(code in currencies)) {
+ const codes = Object.keys (currencies);
+ throw new ExchangeError (this.id + ' fetch ' + code + ' deposit address not supported. Currency code must be one of ' + codes.toString ());
+ }
+ const request = this.extend ({
+ 'code': code,
+ }, params);
+ const response = await this.privateGetDepositAddressesCode (request);
+ // {
+ // "type": "deposit_addresses",
+ // "currency": {
+ // "type": "deposit_currency",
+ // "id": "ERGO",
+ // "waves_asset_id": "5dJj4Hn9t2Ve3tRpNGirUHy4yBK6qdJRAJYV21yPPuGz",
+ // "decimals": 9,
+ // "status": "active",
+ // "allowed_amount": {
+ // "min": 0.001,
+ // "max": 100000
+ // },
+ // "fees": {
+ // "flat": 0,
+ // "rate": 0
+ // }
+ // },
+ // "deposit_addresses": [
+ // "9fRAAQjF8Yqg7qicQCL884zjimsRnuwsSavsM1rUdDaoG8mThku"
+ // ]
+ // }
+ const addresses = this.safeValue (response, 'deposit_addresses');
+ const address = this.safeString (addresses, 0);
+ return {
+ 'address': address,
+ 'code': code,
+ 'tag': undefined,
+ 'info': response,
+ };
+ }
+
+ async getMatcherPublicKey () {
+ // this method returns a single string
+ const matcherPublicKey = this.safeString (this.options, 'matcherPublicKey');
+ if (matcherPublicKey) {
+ return matcherPublicKey;
+ } else {
+ const response = await this.matcherGetMatcher ();
+ // remove trailing quotes from string response
+ this.options['matcherPublicKey'] = response.slice (1, response.length - 1);
+ return this.options['matcherPublicKey'];
+ }
+ }
+
+ getAssetBytes (currencyId) {
+ if (currencyId === 'WAVES') {
+ return this.numberToBE (0, 1);
+ } else {
+ return this.binaryConcat (this.numberToBE (1, 1), this.base58ToBinary (currencyId));
+ }
+ }
+
+ getAssetId (currencyId) {
+ if (currencyId === 'WAVES') {
+ return '';
+ }
+ return currencyId;
+ }
+
+ priceToPrecision (symbol, price) {
+ const market = this.markets[symbol];
+ const wavesPrecision = this.safeInteger (this.options, 'wavesPrecision', 8);
+ const difference = market['precision']['amount'] - market['precision']['price'];
+ return parseInt (parseFloat (this.toWei (price, wavesPrecision - difference)));
+ }
+
+ amountToPrecision (symbol, amount) {
+ return parseInt (parseFloat (this.toWei (amount, this.markets[symbol]['precision']['amount'])));
+ }
+
+ currencyToPrecision (currency, amount) {
+ return parseInt (parseFloat (this.toWei (amount, this.currencies[currency]['precision'])));
+ }
+
+ currencyFromPrecision (currency, amount) {
+ return this.fromWei (amount, this.currencies[currency]['precision']);
+ }
+
+ priceFromPrecision (symbol, price) {
+ const market = this.markets[symbol];
+ const wavesPrecision = this.safeInteger (this.options, 'wavesPrecision', 8);
+ const difference = market['precision']['amount'] - market['precision']['price'];
+ return this.fromWei (price, wavesPrecision - difference);
+ }
+
+ getDefaultExpiry () {
+ const expiry = this.safeInteger (this.options, 'createOrderDefaultExpiry');
+ if (expiry) {
+ return expiry;
+ } else {
+ this.options['createOrderDefaultExpiry'] = 60 * 60 * 24 * 28 * 1000;
+ return this.options['createOrderDefaultExpiry'];
+ }
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ this.checkRequiredDependencies ();
+ this.checkRequiredKeys ();
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const matcherPublicKey = await this.getMatcherPublicKey ();
+ const amountAsset = this.getAssetId (market['baseId']);
+ const priceAsset = this.getAssetId (market['quoteId']);
+ amount = this.amountToPrecision (symbol, amount);
+ price = this.priceToPrecision (symbol, price);
+ const orderType = (side === 'buy') ? 0 : 1;
+ const timestamp = this.milliseconds ();
+ const expiration = this.sum (timestamp, this.getDefaultExpiry ());
+ const settings = await this.matcherGetMatcherSettings ();
+ // {
+ // "orderVersions": [
+ // 1,
+ // 2,
+ // 3
+ // ],
+ // "success": true,
+ // "matcherPublicKey": "9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5",
+ // "orderFee": {
+ // "dynamic": {
+ // "baseFee": 300000,
+ // "rates": {
+ // "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ": 1.0257813,
+ // "62LyMjcr2DtiyF5yVXFhoQ2q414VPPJXjsNYp72SuDCH": 0.01268146,
+ // "HZk1mbfuJpmxU1Fs4AX5MWLVYtctsNcg6e2C6VKqK8zk": 0.05232404,
+ // "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS": 0.00023985,
+ // "4LHHvYGNKJUg5hj65aGD5vgScvCBmLpdRFtjokvCjSL8": 19.5967716,
+ // "474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu": 0.00937073,
+ // "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p": 2.19825,
+ // "B3uGHFRpSUuGEDWjqB9LWWxafQj8VTvpMucEyoxzws5H": 0.03180264,
+ // "zMFqXuoyrn5w17PFurTqxB7GsS71fp9dfk6XFwxbPCy": 0.00996631,
+ // "5WvPKSJXzVE2orvbkJ8wsQmmQKqTv9sGBPksV4adViw3": 0.03254476,
+ // "WAVES": 1,
+ // "BrjUWjndUanm5VsJkbUip8VRYy6LWJePtxya3FNv4TQa": 0.03703704
+ // }
+ // }
+ // },
+ // "networkByte": 87,
+ // "matcherVersion": "2.1.4.8",
+ // "status": "SimpleResponse",
+ // "priceAssets": [
+ // "Ft8X1v1LTa1ABafufpaCWyVj8KkaxUWE6xBhW6sNFJck",
+ // "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p",
+ // "34N9YcEETLWn93qYQ64EsP1x89tSruJU44RrEMSXXEPJ",
+ // "Gtb1WRznfchDnTh37ezoDTJ4wcoKaRsKqKjJjy7nm2zU",
+ // "2mX5DzVKWrAJw8iwdJnV2qtoeVG9h5nTDpTqC1wb1WEN",
+ // "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS",
+ // "WAVES",
+ // "474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu",
+ // "zMFqXuoyrn5w17PFurTqxB7GsS71fp9dfk6XFwxbPCy",
+ // "62LyMjcr2DtiyF5yVXFhoQ2q414VPPJXjsNYp72SuDCH",
+ // "HZk1mbfuJpmxU1Fs4AX5MWLVYtctsNcg6e2C6VKqK8zk",
+ // "B3uGHFRpSUuGEDWjqB9LWWxafQj8VTvpMucEyoxzws5H",
+ // "5WvPKSJXzVE2orvbkJ8wsQmmQKqTv9sGBPksV4adViw3",
+ // "BrjUWjndUanm5VsJkbUip8VRYy6LWJePtxya3FNv4TQa",
+ // "4LHHvYGNKJUg5hj65aGD5vgScvCBmLpdRFtjokvCjSL8"
+ // ]
+ // }
+ const orderFee = this.safeValue (settings, 'orderFee');
+ const dynamic = this.safeValue (orderFee, 'dynamic');
+ const baseMatcherFee = this.safeInteger (dynamic, 'baseFee');
+ const wavesMatcherFee = this.currencyFromPrecision ('WAVES', baseMatcherFee);
+ const rates = this.safeValue (dynamic, 'rates');
+ // choose sponsored assets from the list of priceAssets above
+ const priceAssets = Object.keys (rates);
+ let matcherFeeAssetId = undefined;
+ let matcherFee = undefined;
+ if ('feeAssetId' in params) {
+ matcherFeeAssetId = params['feeAssetId'];
+ } else if ('feeAssetId' in this.options) {
+ matcherFeeAssetId = this.options['feeAssetId'];
+ } else {
+ const balances = await this.fetchBalance ();
+ if (balances['WAVES']['free'] > wavesMatcherFee) {
+ matcherFeeAssetId = 'WAVES';
+ matcherFee = baseMatcherFee;
+ } else {
+ for (let i = 0; i < priceAssets.length; i++) {
+ const assetId = priceAssets[i];
+ const code = this.safeCurrencyCode (assetId);
+ const balance = this.safeValue (this.safeValue (balances, code, {}), 'free');
+ const assetFee = rates[assetId] * wavesMatcherFee;
+ if ((balance !== undefined) && (balance > assetFee)) {
+ matcherFeeAssetId = assetId;
+ break;
+ }
+ }
+ }
+ }
+ if (matcherFeeAssetId === undefined) {
+ throw InsufficientFunds (this.id + ' not enough funds to cover the fee, specify feeAssetId in params or options, or buy some WAVES');
+ }
+ if (matcherFee === undefined) {
+ const wavesPrecision = this.safeInteger (this.options, 'wavesPrecision', 8);
+ const rate = this.safeFloat (rates, matcherFeeAssetId);
+ const code = this.safeCurrencyCode (matcherFeeAssetId);
+ const currency = this.currency (code);
+ const newPrecison = Math.pow (10, wavesPrecision - currency['precision']);
+ matcherFee = Math.ceil (rate * baseMatcherFee / newPrecison);
+ }
+ const byteArray = [
+ this.numberToBE (3, 1),
+ this.base58ToBinary (this.apiKey),
+ this.base58ToBinary (matcherPublicKey),
+ this.getAssetBytes (market['baseId']),
+ this.getAssetBytes (market['quoteId']),
+ this.numberToBE (orderType, 1),
+ this.numberToBE (price, 8),
+ this.numberToBE (amount, 8),
+ this.numberToBE (timestamp, 8),
+ this.numberToBE (expiration, 8),
+ this.numberToBE (matcherFee, 8),
+ this.getAssetBytes (matcherFeeAssetId),
+ ];
+ const binary = this.binaryConcatArray (byteArray);
+ const signature = this.eddsa (this.binaryToBase16 (binary), this.binaryToBase16 (this.base58ToBinary (this.secret)), 'ed25519');
+ const assetPair = {
+ 'amountAsset': amountAsset,
+ 'priceAsset': priceAsset,
+ };
+ const body = {
+ 'senderPublicKey': this.apiKey,
+ 'matcherPublicKey': matcherPublicKey,
+ 'assetPair': assetPair,
+ 'orderType': side,
+ 'price': price,
+ 'amount': amount,
+ 'timestamp': timestamp,
+ 'expiration': expiration,
+ 'matcherFee': matcherFee,
+ 'signature': signature,
+ 'version': 3,
+ };
+ if (matcherFeeAssetId !== 'WAVES') {
+ body['matcherFeeAssetId'] = matcherFeeAssetId;
+ }
+ const response = await this.matcherPostMatcherOrderbook (body);
+ // { success: true,
+ // message:
+ // { version: 3,
+ // id: 'Do7cDJMf2MJuFyorvxNNuzS42MXSGGEq1r1hGDn1PHiS',
+ // sender: '3P8VzLSa23EW5CVckHbV7d5BoN75fF1hhFH',
+ // senderPublicKey: 'AHXn8nBA4SfLQF7hLQiSn16kxyehjizBGW1TdrmSZ1gF',
+ // matcherPublicKey: '9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5',
+ // assetPair:
+ // { amountAsset: null,
+ // priceAsset: '8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS' },
+ // orderType: 'sell',
+ // amount: 1,
+ // price: 100000000,
+ // timestamp: 1591593117995,
+ // expiration: 1594012317995,
+ // matcherFee: 300000,
+ // matcherFeeAssetId: null,
+ // signature: '2EG8zgE6Ze1X5EYA8DbfFiPXAtC7NniYBAMFbJUbzwVbHmmCKHornQfS5F32NwkHF4623KWq1U6K126h4TTqyVq',
+ // proofs:
+ // [ '2EG8zgE6Ze1X5EYA8DbfFiPXAtC7NniYBAMFbJUbzwVbHmmCKHornQfS5F32NwkHF4623KWq1U6K126h4TTqyVq' ] },
+ // status: 'OrderAccepted' }
+ const value = this.safeValue (response, 'message');
+ return this.parseOrder (value, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ this.checkRequiredDependencies ();
+ this.checkRequiredKeys ();
+ await this.getAccessToken ();
+ const wavesAddress = await this.getWavesAddress ();
+ const response = await this.forwardPostMatcherOrdersWavesAddressCancel ({
+ 'wavesAddress': wavesAddress,
+ 'orderId': id,
+ });
+ // {
+ // "success":true,
+ // "message":[[{"orderId":"EBpJeGM36KKFz5gTJAUKDBm89V8wqxKipSFBdU35AN3c","success":true,"status":"OrderCanceled"}]],
+ // "status":"BatchCancelCompleted"
+ // }
+ const message = this.safeValue (response, 'message');
+ const firstMessage = this.safeValue (message, 0);
+ const firstOrder = this.safeValue (firstMessage, 0);
+ const returnedId = this.safeString (firstOrder, 'orderId');
+ return {
+ 'info': response,
+ 'id': returnedId,
+ 'clientOrderId': undefined,
+ 'timestamp': undefined,
+ 'datetime': undefined,
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': undefined,
+ 'side': undefined,
+ 'price': undefined,
+ 'amount': undefined,
+ 'cost': undefined,
+ 'average': undefined,
+ 'filled': undefined,
+ 'remaining': undefined,
+ 'status': undefined,
+ 'fee': undefined,
+ 'trades': undefined,
+ };
+ }
+
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ this.checkRequiredDependencies ();
+ this.checkRequiredKeys ();
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrders requires symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const timestamp = this.milliseconds ();
+ const byteArray = [
+ this.base58ToBinary (this.apiKey),
+ this.numberToBE (timestamp, 8),
+ ];
+ const binary = this.binaryConcatArray (byteArray);
+ const hexSecret = this.binaryToBase16 (this.base58ToBinary (this.secret));
+ const signature = this.eddsa (this.binaryToBase16 (binary), hexSecret, 'ed25519');
+ const request = {
+ 'Accept': 'application/json',
+ 'Timestamp': timestamp.toString (),
+ 'Signature': signature,
+ 'publicKey': this.apiKey,
+ 'baseId': market['baseId'],
+ 'quoteId': market['quoteId'],
+ };
+ const response = await this.matcherGetMatcherOrderbookBaseIdQuoteIdPublicKeyPublicKey (this.extend (request, params));
+ // [ { id: '3KicDeWayY2mdrRoYdCkP3gUAoUZUNT1AA6GAtWuPLfa',
+ // type: 'sell',
+ // orderType: 'limit',
+ // amount: 1,
+ // fee: 300000,
+ // price: 100000000,
+ // timestamp: 1591651254076,
+ // filled: 0,
+ // filledFee: 0,
+ // feeAsset: 'WAVES',
+ // status: 'Accepted',
+ // assetPair:
+ // { amountAsset: null,
+ // priceAsset: '8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS' },
+ // avgWeighedPrice: 0 }, ... ]
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.getAccessToken ();
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ const address = await this.getWavesAddress ();
+ const request = {
+ 'address': address,
+ 'activeOnly': true,
+ };
+ const response = await this.forwardGetMatcherOrdersAddress (request);
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.getAccessToken ();
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ const address = await this.getWavesAddress ();
+ const request = {
+ 'address': address,
+ 'closedOnly': true,
+ };
+ const response = await this.forwardGetMatcherOrdersAddress (request);
+ // [
+ // {
+ // "id": "9aXcxvXai73jbAm7tQNnqaQ2PwUjdmWuyjvRTKAHsw4f",
+ // "type": "buy",
+ // "orderType": "limit",
+ // "amount": 23738330,
+ // "fee": 300000,
+ // "price": 3828348334,
+ // "timestamp": 1591926905636,
+ // "filled": 23738330,
+ // "filledFee": 300000,
+ // "feeAsset": "WAVES",
+ // "status": "Filled",
+ // "assetPair": {
+ // "amountAsset": "HZk1mbfuJpmxU1Fs4AX5MWLVYtctsNcg6e2C6VKqK8zk",
+ // "priceAsset": null
+ // },
+ // "avgWeighedPrice": 3828348334
+ // }, ...
+ // ]
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'Cancelled': 'canceled',
+ 'Accepted': 'open',
+ 'Filled': 'closed',
+ 'PartiallyFilled': 'open',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ getSymbolFromAssetPair (assetPair) {
+ // a blank string or null can indicate WAVES
+ const baseId = this.safeString (assetPair, 'amountAsset', 'WAVES');
+ const quoteId = this.safeString (assetPair, 'priceAsset', 'WAVES');
+ return this.safeCurrencyCode (baseId) + '/' + this.safeCurrencyCode (quoteId);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // version: 3,
+ // id: 'BshyeHXDfJmTnjTdBYt371jD4yWaT3JTP6KpjpsiZepS',
+ // sender: '3P8VzLSa23EW5CVckHbV7d5BoN75fF1hhFH',
+ // senderPublicKey: 'AHXn8nBA4SfLQF7hLQiSn16kxyehjizBGW1TdrmSZ1gF',
+ // matcherPublicKey: '9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5',
+ // assetPair: {
+ // amountAsset: '474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu',
+ // priceAsset: 'DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p'
+ // },
+ // orderType: 'buy',
+ // amount: 10000,
+ // price: 400000000,
+ // timestamp: 1599848586891,
+ // expiration: 1602267786891,
+ // matcherFee: 3008,
+ // matcherFeeAssetId: '474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu',
+ // signature: '3D2h8ubrhuWkXbVn4qJ3dvjmZQxLoRNfjTqb9uNpnLxUuwm4fGW2qGH6yKFe2SQPrcbgkS3bDVe7SNtMuatEJ7qy',
+ // proofs: [
+ // '3D2h8ubrhuWkXbVn4qJ3dvjmZQxLoRNfjTqb9uNpnLxUuwm4fGW2qGH6yKFe2SQPrcbgkS3bDVe7SNtMuatEJ7qy'
+ // ]
+ // }
+ //
+ // fetchClosedOrders
+ //
+ // {
+ // id: '81D9uKk2NfmZzfG7uaJsDtxqWFbJXZmjYvrL88h15fk8',
+ // type: 'buy',
+ // orderType: 'limit',
+ // amount: 30000000000,
+ // filled: 0,
+ // price: 1000000,
+ // fee: 300000,
+ // filledFee: 0,
+ // feeAsset: 'WAVES',
+ // timestamp: 1594303779322,
+ // status: 'Cancelled',
+ // assetPair: {
+ // amountAsset: '474jTeYx2r2Va35794tCScAXWJG9hU2HcgxzMowaZUnu',
+ // priceAsset: 'WAVES'
+ // },
+ // avgWeighedPrice: 0,
+ // version: 3
+ // }
+ //
+ const timestamp = this.safeInteger (order, 'timestamp');
+ const side = this.safeString2 (order, 'type', 'orderType');
+ let type = 'limit';
+ if ('type' in order) {
+ // fetchOrders
+ type = this.safeString (order, 'orderType', type);
+ }
+ const id = this.safeString (order, 'id');
+ let filled = this.safeString (order, 'filled');
+ let price = this.safeString (order, 'price');
+ let amount = this.safeString (order, 'amount');
+ const assetPair = this.safeValue (order, 'assetPair');
+ let symbol = undefined;
+ if (assetPair !== undefined) {
+ symbol = this.getSymbolFromAssetPair (assetPair);
+ } else if (market !== undefined) {
+ symbol = market['symbol'];
+ }
+ const amountCurrency = this.safeCurrencyCode (this.safeString (assetPair, 'amountAsset', 'WAVES'));
+ price = this.priceFromPrecision (symbol, price);
+ amount = this.currencyFromPrecision (amountCurrency, amount);
+ let cost = undefined;
+ if ((price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ filled = this.currencyFromPrecision (amountCurrency, filled);
+ let remaining = undefined;
+ if ((filled !== undefined) && (amount !== undefined)) {
+ remaining = amount - filled;
+ }
+ const average = this.priceFromPrecision (symbol, this.safeString (order, 'avgWeighedPrice'));
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ let fee = undefined;
+ if ('type' in order) {
+ const currency = this.safeCurrencyCode (this.safeString (order, 'feeAsset'));
+ fee = {
+ 'currency': currency,
+ 'fee': this.currencyFromPrecision (currency, this.safeInteger (order, 'filledFee')),
+ };
+ } else {
+ const currency = this.safeCurrencyCode (this.safeString (order, 'matcherFeeAssetId', 'WAVES'));
+ fee = {
+ 'currency': currency,
+ 'fee': this.currencyFromPrecision (currency, this.safeInteger (order, 'matcherFee')),
+ };
+ }
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': undefined,
+ };
+ }
+
+ async getWavesAddress () {
+ const cachedAddreess = this.safeString (this.options, 'wavesAddress');
+ if (cachedAddreess === undefined) {
+ const request = {
+ 'publicKey': this.apiKey,
+ };
+ const response = await this.nodeGetAddressesPublicKeyPublicKey (request);
+ this.options['wavesAddress'] = this.safeString (response, 'address');
+ return this.options['wavesAddress'];
+ } else {
+ return cachedAddreess;
+ }
+ }
+
+ async fetchBalance (params = {}) {
+ // makes a lot of different requests to get all the data
+ // in particular:
+ // fetchMarkets, getWavesAddress,
+ // getTotalBalance (doesn't include waves), getReservedBalance (doesn't include waves)
+ // getReservedBalance (includes WAVES)
+ // I couldn't find another way to get all the data
+ this.checkRequiredDependencies ();
+ this.checkRequiredKeys ();
+ await this.loadMarkets ();
+ const wavesAddress = await this.getWavesAddress ();
+ const request = {
+ 'address': wavesAddress,
+ };
+ const totalBalance = await this.nodeGetAssetsBalanceAddress (request);
+ // {
+ // "address": "3P8VzLSa23EW5CVckHbV7d5BoN75fF1hhFH",
+ // "balances": [
+ // {
+ // "assetId": "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p",
+ // "balance": 1177200,
+ // "reissuable": false,
+ // "minSponsoredAssetFee": 7420,
+ // "sponsorBalance": 47492147189709,
+ // "quantity": 999999999775381400,
+ // "issueTransaction": {
+ // "senderPublicKey": "BRnVwSVctnV8pge5vRpsJdWnkjWEJspFb6QvrmZvu3Ht",
+ // "quantity": 1000000000000000000,
+ // "fee": 100400000,
+ // "description": "Neutrino USD",
+ // "type": 3,
+ // "version": 2,
+ // "reissuable": false,
+ // "script": null,
+ // "sender": "3PC9BfRwJWWiw9AREE2B3eWzCks3CYtg4yo",
+ // "feeAssetId": null,
+ // "chainId": 87,
+ // "proofs": [
+ // "3HNpbVkgP69NWSeb9hGYauiQDaXrRXh3tXFzNsGwsAAXnFrA29SYGbLtziW9JLpXEq7qW1uytv5Fnm5XTUMB2BxU"
+ // ],
+ // "assetId": "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p",
+ // "decimals": 6,
+ // "name": "USD-N",
+ // "id": "DG2xFkPdDwKUoBkzGAhQtLpSGzfXLiCYPEzeKH2Ad24p",
+ // "timestamp": 1574429393962
+ // }
+ // }
+ // ]
+ // }
+ const balances = this.safeValue (totalBalance, 'balances');
+ const result = {};
+ for (let i = 0; i < balances.length; i++) {
+ const entry = balances[i];
+ const issueTransaction = this.safeValue (entry, 'issueTransaction');
+ const decimals = this.safeInteger (issueTransaction, 'decimals');
+ const currencyId = this.safeString (entry, 'assetId');
+ const balance = this.safeFloat (entry, 'balance');
+ let code = undefined;
+ if (currencyId in this.currencies_by_id) {
+ code = this.safeCurrencyCode (currencyId);
+ result[code] = this.account ();
+ result[code]['total'] = this.fromWei (balance, decimals);
+ }
+ }
+ const timestamp = this.milliseconds ();
+ const byteArray = [
+ this.base58ToBinary (this.apiKey),
+ this.numberToBE (timestamp, 8),
+ ];
+ const binary = this.binaryConcatArray (byteArray);
+ const hexSecret = this.binaryToBase16 (this.base58ToBinary (this.secret));
+ const signature = this.eddsa (this.binaryToBase16 (binary), hexSecret, 'ed25519');
+ const matcherRequest = {
+ 'publicKey': this.apiKey,
+ 'signature': signature,
+ 'timestamp': timestamp.toString (),
+ };
+ const reservedBalance = await this.matcherGetMatcherBalanceReservedPublicKey (matcherRequest);
+ // { WAVES: 200300000 }
+ const reservedKeys = Object.keys (reservedBalance);
+ for (let i = 0; i < reservedKeys.length; i++) {
+ const currencyId = reservedKeys[i];
+ const code = this.safeCurrencyCode (currencyId);
+ if (!(code in result)) {
+ result[code] = this.account ();
+ }
+ const amount = this.safeFloat (reservedBalance, currencyId);
+ result[code]['used'] = this.currencyFromPrecision (code, amount);
+ }
+ const wavesRequest = {
+ 'address': wavesAddress,
+ };
+ const wavesTotal = await this.nodeGetAddressesBalanceAddress (wavesRequest);
+ // {
+ // "address": "3P8VzLSa23EW5CVckHbV7d5BoN75fF1hhFH",
+ // "confirmations": 0,
+ // "balance": 909085978
+ // }
+ result['WAVES'] = this.safeValue (result, 'WAVES', {});
+ result['WAVES']['total'] = this.currencyFromPrecision ('WAVES', this.safeFloat (wavesTotal, 'balance'));
+ const codes = Object.keys (result);
+ for (let i = 0; i < codes.length; i++) {
+ const code = codes[i];
+ if (this.safeValue (result[code], 'used') === undefined) {
+ result[code]['used'] = 0.0;
+ }
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const address = await this.getWavesAddress ();
+ const request = {
+ 'sender': address,
+ 'amountAsset': market['baseId'],
+ 'priceAsset': market['quoteId'],
+ };
+ const response = await this.publicGetTransactionsExchange (request);
+ const data = this.safeValue (response, 'data');
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'amountAsset': market['baseId'],
+ 'priceAsset': market['quoteId'],
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ if (since !== undefined) {
+ request['timeStart'] = since;
+ }
+ const response = await this.publicGetTransactionsExchange (request);
+ const data = this.safeValue (response, 'data');
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ parseTrade (trade, market = undefined) {
+ // { __type: 'transaction',
+ // data:
+ // { id: 'HSdruioHqvYHeyn9hhyoHdRWPB2bFA8ujeCPZMK6992c',
+ // timestamp: '2020-06-09T19:34:51.897Z',
+ // height: 2099684,
+ // type: 7,
+ // version: 2,
+ // proofs:
+ // [ '26teDHERQgwjjHqEn4REcDotNG8M21xjou3X42XuDuCvrRkQo6aPyrswByH3UrkWG8v27ZAaVNzoxDg4teNcLtde' ],
+ // fee: 0.003,
+ // sender: '3PEjHv3JGjcWNpYEEkif2w8NXV4kbhnoGgu',
+ // senderPublicKey: '9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5',
+ // buyMatcherFee: 0.00299999,
+ // sellMatcherFee: 0.00299999,
+ // price: 0.00012003,
+ // amount: 60.80421562,
+ // order1:
+ // { id: 'CBRwP3ar4oMvvpUiGyfxc1syh41488SDi2GkrjuBDegv',
+ // senderPublicKey: 'DBXSHBz96NFsMu7xh4fi2eT9ZnyxefAHXsMxUayzgC6a',
+ // matcherPublicKey: '9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5',
+ // assetPair: [Object],
+ // orderType: 'buy',
+ // price: 0.00012003,
+ // sender: '3PJfFRgVuJ47UY4ckb74EGzEBzkHXtmG1LA',
+ // amount: 60.80424773,
+ // timestamp: '2020-06-09T19:34:51.885Z',
+ // expiration: '2020-06-10T12:31:31.885Z',
+ // matcherFee: 0.003,
+ // signature: '4cA3ZAb3XAEEXaFG7caqpto5TRbpR5PkhZpxoNQZ9ZReNvjuJQs5a3THnumv7rcqmVUiVtuHAgk2f67ANcqtKyJ8',
+ // matcherFeeAssetId: null },
+ // order2:
+ // { id: 'CHJSLQ6dfSPs6gu2mAegrMUcRiDEDqaj2GKfvptMjS3M',
+ // senderPublicKey: '3RUC4NGFZm9H8VJhSSjJyFLdiE42qNiUagDcZPwjgDf8',
+ // matcherPublicKey: '9cpfKN9suPNvfeUNphzxXMjcnn974eme8ZhWUjaktzU5',
+ // assetPair: [Object],
+ // orderType: 'sell',
+ // price: 0.00012003,
+ // sender: '3P9vKoQpMZtaSkHKpNh977YY9ZPzTuntLAq',
+ // amount: 60.80424773,
+ // timestamp: '2020-06-09T19:34:51.887Z',
+ // expiration: '2020-06-10T12:31:31.887Z',
+ // matcherFee: 0.003,
+ // signature: '3SFyrcqzou2ddZyNisnLYaGhLt5qRjKxH8Nw3s4T5U7CEKGX9DDo8dS27RgThPVGbYF1rYET1FwrWoQ2UFZ6SMTR',
+ // matcherFeeAssetId: null } } }
+ const data = this.safeValue (trade, 'data');
+ const datetime = this.safeString (data, 'timestamp');
+ const timestamp = this.parse8601 (datetime);
+ const id = this.safeString (data, 'id');
+ const price = this.safeFloat (data, 'price');
+ const amount = this.safeFloat (data, 'amount');
+ const order1 = this.safeValue (data, 'order1');
+ const order2 = this.safeValue (data, 'order2');
+ let order = undefined;
+ // order2 arrived after order1
+ if (this.safeString (order1, 'senderPublicKey') === this.apiKey) {
+ order = order1;
+ } else {
+ order = order2;
+ }
+ let symbol = undefined;
+ const assetPair = this.safeValue (order, 'assetPair');
+ if (assetPair !== undefined) {
+ symbol = this.getSymbolFromAssetPair (assetPair);
+ } else if (market !== undefined) {
+ symbol = market['symbol'];
+ }
+ const side = this.safeString (order, 'orderType');
+ const orderId = this.safeString (order, 'id');
+ let cost = undefined;
+ if ((price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ const fee = {
+ 'cost': this.safeFloat (data, 'fee'),
+ 'currency': this.safeCurrencyCode (this.safeString (order, 'matcherFeeAssetId', 'WAVES')),
+ };
+ return {
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': datetime,
+ 'symbol': symbol,
+ 'id': id,
+ 'order': orderId,
+ 'type': undefined,
+ 'side': side,
+ 'takerOrMaker': undefined,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ const errorCode = this.safeString (response, 'error');
+ const success = this.safeValue (response, 'success', true);
+ const Exception = this.safeValue (this.exceptions, errorCode);
+ if (Exception !== undefined) {
+ const message = this.safeString (response, 'message');
+ throw new Exception (this.id + ' ' + message);
+ }
+ const message = this.safeString (response, 'message');
+ if (message === 'Validation Error') {
+ throw new BadRequest (this.id + ' ' + body);
+ }
+ if (!success) {
+ throw new ExchangeError (this.id + ' ' + body);
+ }
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ // currently only works for BTC and WAVES
+ if (code !== 'WAVES') {
+ const supportedCurrencies = await this.privateGetWithdrawCurrencies ();
+ const currencies = {};
+ const items = this.safeValue (supportedCurrencies, 'items', []);
+ for (let i = 0; i < items.length; i++) {
+ const entry = items[i];
+ const currencyCode = this.safeString (entry, 'id');
+ currencies[currencyCode] = true;
+ }
+ if (!(code in currencies)) {
+ const codes = Object.keys (currencies);
+ throw new ExchangeError (this.id + ' fetch ' + code + ' withdrawals are not supported. Currency code must be one of ' + codes.toString ());
+ }
+ }
+ await this.loadMarkets ();
+ const hexChars = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
+ const set = {};
+ for (let i = 0; i < hexChars.length; i++) {
+ const key = hexChars[i];
+ set[key] = true;
+ }
+ let isErc20 = true;
+ const noPrefix = this.remove0xPrefix (address);
+ const lower = noPrefix.toLowerCase ();
+ for (let i = 0; i < lower.length; i++) {
+ const character = lower[i];
+ if (!(character in set)) {
+ isErc20 = false;
+ break;
+ }
+ }
+ await this.getAccessToken ();
+ let proxyAddress = undefined;
+ if (code === 'WAVES' && !isErc20) {
+ proxyAddress = address;
+ } else {
+ const withdrawAddressRequest = {
+ 'address': address,
+ 'currency': code,
+ };
+ const withdrawAddress = await this.privateGetWithdrawAddressesCurrencyAddress (withdrawAddressRequest);
+ const currency = this.safeValue (withdrawAddress, 'currency');
+ const allowedAmount = this.safeValue (currency, 'allowed_amount');
+ const minimum = this.safeFloat (allowedAmount, 'min');
+ if (amount <= minimum) {
+ throw new BadRequest (this.id + ' ' + code + ' withdraw failed, amount ' + amount.toString () + ' must be greater than the minimum allowed amount of ' + minimum.toString ());
+ }
+ // {
+ // "type": "withdrawal_addresses",
+ // "currency": {
+ // "type": "withdrawal_currency",
+ // "id": "BTC",
+ // "waves_asset_id": "8LQW8f7P5d5PZM7GtZEBgaqRPGSzS3DfPuiXrURJ4AJS",
+ // "decimals": 8,
+ // "status": "active",
+ // "allowed_amount": {
+ // "min": 0.001,
+ // "max": 20
+ // },
+ // "fees": {
+ // "flat": 0.001,
+ // "rate": 0
+ // }
+ // },
+ // "proxy_addresses": [
+ // "3P3qqmkiLwNHB7x1FeoE8bvkRtULwGpo9ga"
+ // ]
+ // }
+ const proxyAddresses = this.safeValue (withdrawAddress, 'proxy_addresses', []);
+ proxyAddress = this.safeString (proxyAddresses, 0);
+ }
+ const fee = this.safeInteger (this.options, 'withdrawFeeWAVES', 100000); // 0.001 WAVES
+ const feeAssetId = 'WAVES';
+ const type = 4; // transfer
+ const version = 2;
+ const amountInteger = this.currencyToPrecision (code, amount);
+ const currency = this.currency (code);
+ const timestamp = this.milliseconds ();
+ const byteArray = [
+ this.numberToBE (4, 1),
+ this.numberToBE (2, 1),
+ this.base58ToBinary (this.apiKey),
+ this.getAssetBytes (currency['id']),
+ this.getAssetBytes (feeAssetId),
+ this.numberToBE (timestamp, 8),
+ this.numberToBE (amountInteger, 8),
+ this.numberToBE (fee, 8),
+ this.base58ToBinary (proxyAddress),
+ this.numberToBE (0, 2),
+ ];
+ const binary = this.binaryConcatArray (byteArray);
+ const hexSecret = this.binaryToBase16 (this.base58ToBinary (this.secret));
+ const signature = this.eddsa (this.binaryToBase16 (binary), hexSecret, 'ed25519');
+ const request = {
+ 'senderPublicKey': this.apiKey,
+ 'amount': amountInteger,
+ 'fee': fee,
+ 'type': type,
+ 'version': version,
+ 'attachment': '',
+ 'feeAssetId': this.getAssetId (feeAssetId),
+ 'proofs': [
+ signature,
+ ],
+ 'assetId': this.getAssetId (currency['id']),
+ 'recipient': proxyAddress,
+ 'timestamp': timestamp,
+ 'signature': signature,
+ };
+ return await this.nodePostTransactionsBroadcast (request);
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7}],174:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -110900,6 +132446,7 @@ module.exports = class whitebit extends Exchange {
'fetchTicker': true,
'fetchTickers': true,
'fetchTrades': true,
+ 'fetchTradingFees': true,
'privateAPI': false,
'publicAPI': true,
},
@@ -110928,7 +132475,7 @@ module.exports = class whitebit extends Exchange {
'publicV1': 'https://whitebit.com/api/v1/public',
},
'www': 'https://www.whitebit.com',
- 'doc': 'https://documenter.getpostman.com/view/7473075/SVSPomwS?version=latest#intro',
+ 'doc': 'https://documenter.getpostman.com/view/7473075/Szzj8dgv?version=latest',
'fees': 'https://whitebit.com/fee-schedule',
'referral': 'https://whitebit.com/referral/d9bdf40e-28f2-4b52-b2f9-cd1415d82963',
},
@@ -111245,19 +132792,10 @@ module.exports = class whitebit extends Exchange {
const result = {};
for (let i = 0; i < marketIds.length; i++) {
const marketId = marketIds[i];
- let market = undefined;
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ const market = this.safeMarket (marketId);
const ticker = this.parseTicker (data[marketId], market);
- result[symbol] = this.extend (ticker, { 'symbol': symbol });
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
}
return this.filterByArray (result, 'symbol', symbols);
}
@@ -111429,24 +132967,55 @@ module.exports = class whitebit extends Exchange {
'interval': this.timeframes[timeframe],
};
if (since !== undefined) {
- request['start'] = parseInt (since / 1000);
+ const maxLimit = 1440;
+ if (limit === undefined) {
+ limit = maxLimit;
+ }
+ limit = Math.min (limit, maxLimit);
+ const start = parseInt (since / 1000);
+ const duration = this.parseTimeframe (timeframe);
+ const end = this.sum (start, duration * limit);
+ request['start'] = start;
+ request['end'] = end;
}
if (limit !== undefined) {
- request['limit'] = limit; // default == max == 500
+ request['limit'] = limit; // max 1440
}
const response = await this.publicV1GetKline (this.extend (request, params));
- const result = this.safeValue (response, 'result');
+ //
+ // {
+ // "success":true,
+ // "message":"",
+ // "result":[
+ // [1591488000,"0.025025","0.025025","0.025029","0.025023","6.181","0.154686629"],
+ // [1591488060,"0.025028","0.025033","0.025035","0.025026","8.067","0.201921167"],
+ // [1591488120,"0.025034","0.02505","0.02505","0.025034","20.089","0.503114696"],
+ // ]
+ // }
+ //
+ const result = this.safeValue (response, 'result', []);
return this.parseOHLCVs (result, market, timeframe, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591488000,
+ // "0.025025",
+ // "0.025025",
+ // "0.025029",
+ // "0.025023",
+ // "6.181",
+ // "0.154686629"
+ // ]
+ //
return [
- ohlcv[0] * 1000, // timestamp
- parseFloat (ohlcv[1]), // open
- parseFloat (ohlcv[3]), // high
- parseFloat (ohlcv[4]), // low
- parseFloat (ohlcv[2]), // close
- parseFloat (ohlcv[5]), // volume
+ this.safeTimestamp (ohlcv, 0), // timestamp
+ this.safeFloat (ohlcv, 1), // open
+ this.safeFloat (ohlcv, 3), // high
+ this.safeFloat (ohlcv, 4), // low
+ this.safeFloat (ohlcv, 2), // close
+ this.safeFloat (ohlcv, 5), // volume
];
}
@@ -111495,7 +133064,7 @@ module.exports = class whitebit extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],169:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],175:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -111514,10 +133083,17 @@ module.exports = class xbtce extends Exchange {
'rateLimit': 2000, // responses are cached every 2 seconds
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchTickers': true,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchOHLCV': false,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'referral': 'https://xbtce.com/?agent=XX97BTCXXXG687021000B',
@@ -111734,7 +133310,7 @@ module.exports = class xbtce extends Exchange {
const ticker = tickers[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -111759,14 +133335,14 @@ module.exports = class xbtce extends Exchange {
return await this.privateGetTrade (params);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
return [
- ohlcv['Timestamp'],
- ohlcv['Open'],
- ohlcv['High'],
- ohlcv['Low'],
- ohlcv['Close'],
- ohlcv['Volume'],
+ this.safeInteger (ohlcv, 'Timestamp'),
+ this.safeFloat (ohlcv, 'Open'),
+ this.safeFloat (ohlcv, 'High'),
+ this.safeFloat (ohlcv, 'Low'),
+ this.safeFloat (ohlcv, 'Close'),
+ this.safeFloat (ohlcv, 'Volume'),
];
}
@@ -111853,20 +133429,1737 @@ module.exports = class xbtce extends Exchange {
auth += body;
}
const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256', 'base64');
- const credentials = this.uid + ':' + this.apiKey + ':' + nonce + ':' + this.decode (signature);
+ const credentials = this.uid + ':' + this.apiKey + ':' + nonce + ':' + signature;
headers['Authorization'] = 'HMAC ' + credentials;
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
};
-},{"./base/Exchange":7,"./base/errors":9}],170:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],176:[function(require,module,exports){
+'use strict';
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, ArgumentsRequired, BadRequest, InsufficientFunds, InvalidAddress, BadSymbol, InvalidOrder } = require ('./base/errors');
+
+module.exports = class xena extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'xena',
+ 'name': 'Xena Exchange',
+ 'countries': [ 'VC', 'UK' ],
+ 'rateLimit': 100,
+ 'certified': true,
+ 'has': {
+ 'CORS': false,
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'createDepositAddress': true,
+ 'createOrder': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87489843-bb469280-c64c-11ea-91aa-69c6326506af.jpg',
+ 'api': {
+ 'public': 'https://trading.xena.exchange/api',
+ 'private': 'https://api.xena.exchange',
+ },
+ 'www': 'https://xena.exchange',
+ 'doc': 'https://support.xena.exchange/support/solutions/44000808700',
+ 'fees': 'https://trading.xena.exchange/en/platform-specification/fee-schedule',
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '5m': '5m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '4h': '4h',
+ '12h': '12h',
+ '1d': '1d',
+ '1w': '1w',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'common/currencies',
+ 'common/instruments',
+ 'common/features',
+ 'common/commissions',
+ 'common/news',
+ 'market-data/candles/{marketId}/{timeframe}',
+ 'market-data/market-watch',
+ 'market-data/dom/{symbol}',
+ 'market-data/candles/{symbol}/{timeframe}',
+ 'market-data/trades/{symbol}',
+ 'market-data/server-time',
+ 'market-data/v2/candles/{symbol}/{timeframe}',
+ 'market-data/v2/trades/{symbol}',
+ 'market-data/v2/dom/{symbol}/',
+ 'market-data/v2/server-time',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'trading/accounts/{accountId}/order',
+ 'trading/accounts/{accountId}/active-orders',
+ 'trading/accounts/{accountId}/last-order-statuses',
+ 'trading/accounts/{accountId}/positions',
+ 'trading/accounts/{accountId}/positions-history',
+ 'trading/accounts/{accountId}/margin-requirements',
+ 'trading/accounts',
+ 'trading/accounts/{accountId}/balance',
+ 'trading/accounts/{accountId}/trade-history',
+ // 'trading/accounts/{accountId}/trade-history?symbol=BTC/USDT&client_order_id=EMBB8Veke&trade_id=220143254',
+ 'transfers/accounts',
+ 'transfers/accounts/{accountId}',
+ 'transfers/accounts/{accountId}/deposit-address/{currency}',
+ 'transfers/accounts/{accountId}/deposits',
+ 'transfers/accounts/{accountId}/trusted-addresses',
+ 'transfers/accounts/{accountId}/withdrawals',
+ 'transfers/accounts/{accountId}/balance-history',
+ // 'transfers/accounts/{accountId}/balance-history?currency={currency}&from={time}&to={time}&kind={kind}&kind={kind}',
+ // 'transfers/accounts/{accountId}/balance-history?page={page}&limit={limit}',
+ // 'transfers/accounts/{accountId}/balance-history?txid=3e1db982c4eed2d6355e276c5bae01a52a27c9cef61574b0e8c67ee05fc26ccf',
+ ],
+ 'post': [
+ 'trading/order/new',
+ 'trading/order/heartbeat',
+ 'trading/order/cancel',
+ 'trading/order/mass-cancel',
+ 'trading/order/replace',
+ 'trading/position/maintenance',
+ 'transfers/accounts/{accountId}/withdrawals',
+ 'transfers/accounts/{accountId}/deposit-address/{currency}',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'maker': 0.0005,
+ 'taker': 0.001,
+ 'tierBased': true,
+ 'percentage': true,
+ },
+ 'funding': {
+ 'tierBased': false,
+ 'percentage': false,
+ 'withdraw': {},
+ 'deposit': {},
+ },
+ },
+ 'exceptions': {
+ 'exact': {
+ 'Validation failed': BadRequest,
+ 'Unknown derivative symbol': BadSymbol, // {"error":"Unknown derivative symbol"}
+ 'Unknown account': BadRequest, // {"error":"Unknown account"}
+ 'Wrong TransactTime': BadRequest, // {"error":"Wrong TransactTime"}
+ 'ClOrdId is empty': BadRequest, // {"error":"ClOrdId is empty"}
+ },
+ 'broad': {
+ 'Invalid aggregation ratio or depth': BadRequest,
+ 'address': InvalidAddress,
+ 'Money not enough': InsufficientFunds,
+ 'parse error': BadRequest,
+ 'Not enough': InsufficientFunds, // {"error":"Not enough free margin"}
+ },
+ },
+ 'options': {
+ 'defaultType': 'margin', // 'margin',
+ 'accountId': undefined, // '1012838157',
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetMarketDataV2ServerTime (params);
+ //
+ // {
+ // "msgType":"0",
+ // "transactTime":1594774454112817637
+ // }
+ //
+ const transactTime = this.safeInteger (response, 'transactTime');
+ return parseInt (transactTime / 1000000);
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetCommonInstruments (params);
+ //
+ // [
+ // {
+ // "id":"ETHUSD_3M_250920",
+ // "type":"Margin",
+ // "marginType":"XenaFuture",
+ // "symbol":"ETHUSD_3M_250920",
+ // "baseCurrency":"ETH",
+ // "quoteCurrency":"USD",
+ // "settlCurrency":"BTC",
+ // "tickSize":2,
+ // "minOrderQuantity":"1",
+ // "orderQtyStep":"1",
+ // "limitOrderMaxDistance":"10",
+ // "priceInputMask":"0000.00",
+ // "enabled":true,
+ // "liquidationMaxDistance":"0.01",
+ // "contractValue":"1",
+ // "contractCurrency":"BTC",
+ // "lotSize":"1",
+ // "tickValue":"0.00000001", // linear contracts only
+ // "maxOrderQty":"175000",
+ // "maxPosVolume":"1750000",
+ // "mark":".ETHUSD_3M_250920",
+ // "underlying":".ETHUSD_TWAP",
+ // "openInterest":".ETHUSD_3M_250920_OpenInterest",
+ // "floatingPL":"BidAsk", // perpetual contracts only
+ // "addUvmToFreeMargin":"ProfitAndLoss",
+ // "margin":{
+ // "netting":"PositionsAndOrders",
+ // "rates":[
+ // {"maxVolume":"175000","initialRate":"0.05","maintenanceRate":"0.0125"},
+ // {"maxVolume":"350000","initialRate":"0.1","maintenanceRate":"0.025"},
+ // {"maxVolume":"500000","initialRate":"0.2","maintenanceRate":"0.05"},
+ // {"maxVolume":"750000","initialRate":"0.3","maintenanceRate":"0.075"},
+ // {"maxVolume":"1050000","initialRate":"0.4","maintenanceRate":"0.1"},
+ // {"maxVolume":"1400000","initialRate":"0.5","maintenanceRate":"0.125"},
+ // {"maxVolume":"1750000","initialRate":"1","maintenanceRate":"0.25"}
+ // ],
+ // "rateMultipliers":{
+ // "LimitBuy":"1",
+ // "LimitSell":"1",
+ // "Long":"1",
+ // "MarketBuy":"1",
+ // "MarketSell":"1",
+ // "Short":"1",
+ // "StopBuy":"0",
+ // "StopSell":"0"
+ // }
+ // },
+ // "clearing":{"enabled":true,"index":".ETHUSD_3M_250920"},
+ // "premium":{"enabled":true,"index":".XBTUSD_Premium_IR_Corrected"}, // perpetual contracts only
+ // "riskAdjustment":{"enabled":true,"index":".RiskAdjustment_IR"},
+ // "expiration":{"enabled":true,"index":".ETHUSD_TWAP"}, // futures only
+ // "pricePrecision":3,
+ // "priceRange":{
+ // "enabled":true,
+ // "distance":"0.03",
+ // "movingBoundary":"0",
+ // "lowIndex":".ETHUSD_3M_250920_LOWRANGE",
+ // "highIndex":".ETHUSD_3M_250920_HIGHRANGE"
+ // },
+ // "priceLimits":{
+ // "enabled":true,
+ // "distance":"0.5",
+ // "movingBoundary":"0",
+ // "lowIndex":".ETHUSD_3M_250920_LOWLIMIT",
+ // "highIndex":".ETHUSD_3M_250920_HIGHLIMIT"
+ // },
+ // "inverse":true, // inverse contracts only
+ // "serie":"ETHUSD", // futures only
+ // "tradingStartDate":"2020-03-27 07:00:00",
+ // "expiryDate":"2020-09-25 08:00:00" // futures only
+ // },
+ // {
+ // "type":"Index",
+ // "symbol":".ETHUSD_Premium_IR_Corrected",
+ // "tickSize":6,
+ // "enabled":true,
+ // "basis":365
+ // },
+ // ]
+ //
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ let type = this.safeStringLower (market, 'type');
+ const id = this.safeString (market, 'symbol');
+ const numericId = this.safeString (market, 'id');
+ const marginType = this.safeString (market, 'marginType');
+ const baseId = this.safeString (market, 'baseCurrency');
+ const quoteId = this.safeString (market, 'quoteCurrency');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ let symbol = id;
+ if (type === 'margin') {
+ if (marginType === 'XenaFuture') {
+ type = 'future';
+ } else if (marginType === 'XenaListedPerpetual') {
+ type = 'swap';
+ symbol = base + '/' + quote;
+ }
+ }
+ const future = (type === 'future');
+ const swap = (type === 'swap');
+ const pricePrecision = this.safeInteger2 (market, 'tickSize', 'pricePrecision');
+ const precision = {
+ 'price': pricePrecision,
+ 'amount': 0,
+ };
+ const maxCost = this.safeFloat (market, 'maxOrderQty');
+ const minCost = this.safeFloat (market, 'minOrderQuantity');
+ const limits = {
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': minCost,
+ 'max': maxCost,
+ },
+ };
+ const active = this.safeValue (market, 'enabled', false);
+ const inverse = this.safeValue (market, 'inverse', false);
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'numericId': numericId,
+ 'active': active,
+ 'type': type,
+ 'spot': false,
+ 'future': future,
+ 'swap': swap,
+ 'inverse': inverse,
+ 'precision': precision,
+ 'limits': limits,
+ 'info': market,
+ });
+ }
+ return result;
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCommonCurrencies (params);
+ //
+ // {
+ // "BAB": {
+ // "name":"BAB",
+ // "title":"Bitcoin ABC",
+ // "blockchain":{
+ // "name":"BAB",
+ // "title":"Bitcoin ABC",
+ // "deposit":{"confirmations":6},
+ // "withdraw":{"confirmations":1},
+ // "addressReuseAllowed":false,
+ // "view":{
+ // "uriTemplate":"bitcoinabc:%s?message=Xena Exchange",
+ // "recommendedFee":"0.00001",
+ // "transactionUrl":"https://blockchair.com/bitcoin-cash/transaction/${txId}",
+ // "walletUrl":"https://blockchair.com/bitcoin-cash/address/${walletId}"
+ // }
+ // },
+ // "precision":5,
+ // "withdraw":{"minAmount":"0.01","commission":"0.001"},
+ // "view":{
+ // "color":"#DC7C08",
+ // "site":"https://www.bitcoinabc.org"
+ // },
+ // "enabled":true
+ // },
+ // }
+ const ids = Object.keys (response);
+ const result = {};
+ for (let i = 0; i < ids.length; i++) {
+ const id = ids[i];
+ const currency = response[id];
+ const code = this.safeCurrencyCode (id);
+ const name = this.safeString (currency, 'title');
+ const precision = this.safeInteger (currency, 'precision');
+ const enabled = this.safeValue (currency, 'enabled');
+ const active = (enabled === true);
+ const withdraw = this.safeValue (currency, 'withdraw', {});
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': currency,
+ 'name': name,
+ 'active': active,
+ 'fee': this.safeFloat (withdraw, 'commission'),
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (withdraw, 'minAmount'),
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ return result;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker, fetchTickers
+ //
+ // {
+ // "symbol":".XBTUSD_3M_250920_MID",
+ // "firstPx":"9337.49",
+ // "lastPx":"9355.81",
+ // "highPx":"9579.42",
+ // "lowPx":"9157.63",
+ // "buyVolume":"0",
+ // "sellVolume":"0",
+ // "bid":"0",
+ // "ask":"0"
+ // }
+ //
+ const timestamp = this.milliseconds ();
+ const marketId = this.safeString (ticker, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
+ const last = this.safeFloat (ticker, 'lastPx');
+ const open = this.safeFloat (ticker, 'firstPx');
+ let percentage = undefined;
+ let change = undefined;
+ let average = undefined;
+ if ((last !== undefined) && (open !== undefined)) {
+ change = last - open;
+ average = this.sum (last, open) / 2;
+ if (open > 0) {
+ percentage = change / open * 100;
+ }
+ }
+ const buyVolume = this.safeFloat (ticker, 'buyVolume');
+ const sellVolume = this.safeFloat (ticker, 'sellVolume');
+ const baseVolume = this.sum (buyVolume, sellVolume);
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'highPx'),
+ 'low': this.safeFloat (ticker, 'lowPx'),
+ 'bid': this.safeFloat (ticker, 'bid'),
+ 'bidVolume': undefined,
+ 'ask': this.safeFloat (ticker, 'ask'),
+ 'askVolume': undefined,
+ 'vwap': undefined,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': undefined,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const tickers = await this.fetchTickers (undefined, params);
+ if (symbol in tickers) {
+ return tickers[symbol];
+ }
+ throw new BadSymbol (this.id + ' fetchTicker could not find a ticker with symbol ' + symbol);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const tickers = await this.publicGetMarketDataMarketWatch (params);
+ //
+ // [
+ // {
+ // "symbol":".XBTUSD_3M_250920_MID",
+ // "firstPx":"9337.49",
+ // "lastPx":"9355.81",
+ // "highPx":"9579.42",
+ // "lowPx":"9157.63",
+ // "buyVolume":"0",
+ // "sellVolume":"0",
+ // "bid":"0",
+ // "ask":"0"
+ // }
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < tickers.length; i++) {
+ const ticker = this.parseTicker (tickers[i]);
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'symbol': this.marketId (symbol),
+ };
+ if (limit !== undefined) {
+ request['depth'] = limit;
+ }
+ const response = await this.publicGetMarketDataV2DomSymbol (this.extend (request, params));
+ //
+ // {
+ // "msgType":"W",
+ // "mdStreamId":"DOM:XBTUSD:aggregated",
+ // "lastUpdateTime":1594772683037691997,
+ // "mdBookType":"2",
+ // "symbol":"XBTUSD",
+ // "lowRangePx":"9132.24",
+ // "highRangePx":"9410.36",
+ // "lowLimitPx":"9132.24",
+ // "highLimitPx":"9410.36",
+ // "clearingPx":"9253.4",
+ // "bestBid":"9269.8",
+ // "bestAsk":"9275.9",
+ // "mdEntry":[
+ // {"mdEntryType":"1","mdEntryPx":"9275.9","mdEntrySize":"3000","numberOfOrders":1},
+ // {"mdEntryType":"1","mdEntryPx":"9277.7","mdEntrySize":"50000","numberOfOrders":1},
+ // {"mdEntryType":"1","mdEntryPx":"9277.8","mdEntrySize":"2000","numberOfOrders":1},
+ // {"mdEntryType":"0","mdEntryPx":"9269.8","mdEntrySize":"2000","numberOfOrders":1},
+ // {"mdEntryType":"0","mdEntryPx":"9267.9","mdEntrySize":"3000","numberOfOrders":1},
+ // {"mdEntryType":"0","mdEntryPx":"9267.8","mdEntrySize":"50000","numberOfOrders":1},
+ // ]
+ // }
+ //
+ const mdEntry = this.safeValue (response, 'mdEntry', []);
+ const mdEntriesByType = this.groupBy (mdEntry, 'mdEntryType');
+ const lastUpdateTime = this.safeInteger (response, 'lastUpdateTime');
+ const timestamp = parseInt (lastUpdateTime / 1000000);
+ return this.parseOrderBook (mdEntriesByType, timestamp, '0', '1', 'mdEntryPx', 'mdEntrySize');
+ }
+
+ async fetchAccounts (params = {}) {
+ const response = await this.privateGetTradingAccounts (params);
+ //
+ // {
+ // "accounts": [
+ // { "id":8273231, "kind": "Spot" },
+ // { "id":10012833469, "kind": "Margin", "currency": "BTC" }
+ // ]
+ // }
+ //
+ const accounts = this.safeValue (response, 'accounts');
+ const result = [];
+ for (let i = 0; i < accounts.length; i++) {
+ const account = accounts[i];
+ const accountId = this.safeString (account, 'id');
+ const currencyId = this.safeString (account, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const type = this.safeStringLower (account, 'kind');
+ result.push ({
+ 'id': accountId,
+ 'type': type,
+ 'currency': code,
+ 'info': account,
+ });
+ }
+ return result;
+ }
+
+ async findAccountByType (type) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountsByType = this.groupBy (this.accounts, 'type');
+ const accounts = this.safeValue (accountsByType, type);
+ if (accounts === undefined) {
+ throw new ExchangeError (this.id + " findAccountByType() could not find an accountId with type '" + type + "', specify the 'accountId' parameter instead"); // eslint-disable-line quotes
+ }
+ const numAccounts = accounts.length;
+ if (numAccounts > 1) {
+ throw new ExchangeError (this.id + " findAccountByType() found more than one accountId with type '" + type + "', specify the 'accountId' parameter instead"); // eslint-disable-line quotes
+ }
+ return accounts[0];
+ }
+
+ async getAccountId (params) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const defaultAccountId = this.safeString (this.options, 'accountId');
+ const accountId = this.safeString (params, 'accountId', defaultAccountId);
+ if (accountId !== undefined) {
+ return accountId;
+ }
+ const defaultType = this.safeString (this.options, 'defaultType', 'margin');
+ const type = this.safeString (params, 'type', defaultType);
+ params = this.omit (params, 'type');
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " requires an 'accountId' parameter or a 'type' parameter ('spot' or 'margin')");
+ }
+ const account = await this.findAccountByType (type);
+ return account['id'];
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const request = {
+ 'accountId': accountId,
+ };
+ const response = await this.privateGetTradingAccountsAccountIdBalance (this.extend (request, params));
+ //
+ // {
+ // "balances": [
+ // {"available":"0","onHold":"0","settled":"0","equity":"0","currency":"BAB","lastUpdated":1564811790485125345},
+ // {"available":"0","onHold":"0","settled":"0","equity":"0","currency":"BSV","lastUpdated":1564811790485125345},
+ // {"available":"0","onHold":"0","settled":"0","equity":"0","currency":"BTC","lastUpdated":1564811790485125345},
+ // ]
+ // }
+ //
+ 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, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['free'] = this.safeFloat (balance, 'available');
+ account['used'] = this.safeFloat (balance, 'onHold');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // {
+ // "mdUpdateAction":"0",
+ // "mdEntryType":"2",
+ // "mdEntryPx":"9225.16",
+ // "mdEntrySize":"10000",
+ // "transactTime":1594728504524977655,
+ // "tradeId":"6ac51bb7-7505-4f35-85ef-61eb738cb4d9",
+ // "aggressorSide":"1"
+ // }
+ //
+ // fetchMyTrades
+ //
+ // {
+ // "msgType":"8",
+ // "account":1012838158,
+ // "clOrdId":"xXWKLQVl3",
+ // "orderId":"89eee8bd-98ae-4d06-97dc-ee2d12997fe7",
+ // "symbol":"ETHUSD",
+ // "transactTime":1595143349089739000,
+ // "execId":"c4bd0ee2330930924e0f6fdde4630e56751692a4",
+ // "tradeId":"30a394b2-6d53-4bc4-b276-d8e19f470ba1",
+ // "side":"2",
+ // "lastQty":"1",
+ // "lastPx":"234.58",
+ // "avgPx":"234.58",
+ // "calculatedCcyLastQty":"0",
+ // "netMoney":"0",
+ // "lastLiquidityInd":"2",
+ // "commission":"0.00000011",
+ // "commRate":"0.00045",
+ // "commCurrency":"BTC",
+ // "positionId":132162662,
+ // "positionEffect":"C"
+ // }
+ //
+ const id = this.safeString (trade, 'tradeId');
+ let timestamp = this.safeInteger (trade, 'transactTime');
+ if (timestamp !== undefined) {
+ timestamp = parseInt (timestamp / 1000000);
+ }
+ let side = this.safeStringLower2 (trade, 'side', 'aggressorSide');
+ if (side === '1') {
+ side = 'buy';
+ } else if (side === '2') {
+ side = 'sell';
+ }
+ const orderId = this.safeString (trade, 'orderId');
+ const marketId = this.safeString (trade, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
+ const price = this.safeFloat2 (trade, 'lastPx', 'mdEntryPx');
+ const amount = this.safeFloat2 (trade, 'lastQty', 'mdEntrySize');
+ let cost = undefined;
+ if (price !== undefined) {
+ if (amount !== undefined) {
+ cost = price * amount;
+ }
+ }
+ let fee = undefined;
+ const feeCost = this.safeFloat (trade, 'commission');
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (trade, 'commCurrency');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ const feeRate = this.safeFloat (trade, 'commRate');
+ fee = {
+ 'cost': feeCost,
+ 'rate': feeRate,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ return {
+ 'id': id,
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'type': undefined,
+ 'order': orderId,
+ 'side': side,
+ 'takerOrMaker': undefined,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const request = {
+ 'accountId': accountId,
+ // 'page': 1,
+ // 'limit': integer,
+ // 'from': time,
+ // 'to': time,
+ // 'symbol': currency['id'],
+ // 'trade_id': id,
+ // 'client_order_id': id,
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['from'] = since * 1000000;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetTradingAccountsAccountIdTradeHistory (this.extend (request, params));
+ //
+ // [
+ // {
+ // "msgType":"8",
+ // "account":1012838158,
+ // "clOrdId":"xXWKLQVl3",
+ // "orderId":"89eee8bd-98ae-4d06-97dc-ee2d12997fe7",
+ // "symbol":"ETHUSD",
+ // "transactTime":1595143349089739000,
+ // "execId":"c4bd0ee2330930924e0f6fdde4630e56751692a4",
+ // "tradeId":"30a394b2-6d53-4bc4-b276-d8e19f470ba1",
+ // "side":"2",
+ // "lastQty":"1",
+ // "lastPx":"234.58",
+ // "avgPx":"234.58",
+ // "calculatedCcyLastQty":"0",
+ // "netMoney":"0",
+ // "lastLiquidityInd":"2",
+ // "commission":"0.00000011",
+ // "commRate":"0.00045",
+ // "commCurrency":"BTC",
+ // "positionId":132162662,
+ // "positionEffect":"C"
+ // },
+ // {
+ // "msgType":"8",
+ // "account":1012838158,
+ // "clOrdId":"3ce8c305-9936-4e97-9206-71ae3ff40305",
+ // "orderId":"a93c686d-990e-44d9-9cbe-61107744b990",
+ // "symbol":"ETHUSD",
+ // "transactTime":1595143315369226000,
+ // "execId":"1c745881722ad966a4ce71600cd058d59da0d1c3",
+ // "tradeId":"77f75bd8-27c4-4b1a-a5e8-0d59239ce216",
+ // "side":"1",
+ // "lastQty":"1",
+ // "lastPx":"234.72",
+ // "avgPx":"234.72",
+ // "calculatedCcyLastQty":"0",
+ // "netMoney":"0",
+ // "lastLiquidityInd":"2",
+ // "commission":"0.00000011",
+ // "commRate":"0.00045",
+ // "commCurrency":"BTC",
+ // "positionId":132162662,
+ // "positionEffect":"O"
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "transactTime":1594784700000000000,
+ // "firstPx":"9246.3",
+ // "lastPx":"9232.8",
+ // "highPx":"9246.3",
+ // "lowPx":"9232.8",
+ // "buyVolume":"0",
+ // "sellVolume":"0"
+ // }
+ //
+ const transactTime = this.safeInteger (ohlcv, 'transactTime');
+ const timestamp = parseInt (transactTime / 1000000);
+ const buyVolume = this.safeFloat (ohlcv, 'buyVolume');
+ const sellVolume = this.safeFloat (ohlcv, 'sellVolume');
+ const volume = this.sum (buyVolume, sellVolume);
+ return [
+ timestamp,
+ this.safeFloat (ohlcv, 'firstPx'),
+ this.safeFloat (ohlcv, 'highPx'),
+ this.safeFloat (ohlcv, 'lowPx'),
+ this.safeFloat (ohlcv, 'lastPx'),
+ volume,
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ 'timeframe': this.timeframes[timeframe],
+ };
+ const durationInSeconds = this.parseTimeframe (timeframe);
+ const duration = durationInSeconds * 1000;
+ if (since !== undefined) {
+ request['from'] = since * 1000000;
+ if (limit !== undefined) {
+ request['to'] = this.sum (since, limit * duration) * 1000000;
+ }
+ } else {
+ const now = this.milliseconds ();
+ // max limit is 1000
+ if (limit !== undefined) {
+ request['from'] = (now - limit * duration) * 1000000;
+ }
+ }
+ const response = await this.publicGetMarketDataV2CandlesSymbolTimeframe (this.extend (request, params));
+ //
+ // {
+ // "mdEntry":[
+ // {"transactTime":1594784700000000000,"firstPx":"9246.3","lastPx":"9232.8","highPx":"9246.3","lowPx":"9232.8","buyVolume":"0","sellVolume":"0"},
+ // {"transactTime":1594785600000000000,"firstPx":"9231.8","lastPx":"9227.3","highPx":"9232.8","lowPx":"9227.3","buyVolume":"0","sellVolume":"0"},
+ // {"transactTime":1594786500000000000,"firstPx":"9226.3","lastPx":"9230.3","highPx":"9230.3","lowPx":"9220.6","buyVolume":"0","sellVolume":"0"}
+ // ]
+ // }
+ //
+ const mdEntry = this.safeValue (response, 'mdEntry', []);
+ return this.parseOHLCVs (mdEntry, market, timeframe, since, limit);
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()),
+ // 'page': 1,
+ // 'limit': limit,
+ };
+ if (since !== undefined) {
+ request['from'] = this.iso8601 (since);
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.publicGetMarketDataV2TradesSymbol (this.extend (request, params));
+ //
+ // {
+ // "msgType":"W",
+ // "lastUpdateTime":1594737830902223803,
+ // "symbol":"XBTUSD",
+ // "mdEntry":[
+ // {
+ // "mdUpdateAction":"0",
+ // "mdEntryType":"2",
+ // "mdEntryPx":"9225.16",
+ // "mdEntrySize":"10000",
+ // "transactTime":1594728504524977655,
+ // "tradeId":"6ac51bb7-7505-4f35-85ef-61eb738cb4d9",
+ // "aggressorSide":"1"
+ // },
+ // ]
+ // }
+ //
+ const mdEntry = this.safeValue (response, 'mdEntry', []);
+ return this.parseTrades (mdEntry, market, since, limit);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'A': 'open', // PendingNew
+ '0': 'open', // New
+ '1': 'open', // PartiallyFilled
+ '2': 'closed', // Filled
+ '6': 'canceled', // PendingCancel
+ '4': 'canceled', // Cancelled
+ 'E': 'open', // PendingReplace
+ '8': 'rejected', // Rejected
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // "msgType":"8",
+ // "account":1012838720,
+ // "clOrdId":"XAq0pRQ1g",
+ // "orderId":"64d7a06a-27e5-422e-99d9-3cadc04f5a35",
+ // "symbol":"XBTUSD",
+ // "ordType":"2",
+ // "price":"9000",
+ // "transactTime":1593778763271127920,
+ // "execId":"ff5fb8153652f0516bf07b6979255bed053c84b9",
+ // "execType":"I",
+ // "ordStatus":"0",
+ // "side":"1",
+ // "orderQty":"1",
+ // "leavesQty":"1",
+ // "cumQty":"0",
+ // "positionEffect":"O",
+ // "marginAmt":"0.00000556",
+ // "marginAmtType":"11"
+ // }
+ //
+ const id = this.safeString (order, 'orderId');
+ const clientOrderId = this.safeString (order, 'clOrdId');
+ const transactTime = this.safeInteger (order, 'transactTime');
+ const timestamp = parseInt (transactTime / 1000000);
+ const status = this.parseOrderStatus (this.safeString (order, 'ordStatus'));
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
+ const price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'orderQty');
+ const filled = this.safeFloat (order, 'cumQty');
+ const remaining = this.safeFloat (order, 'leavesQty');
+ let cost = undefined;
+ let side = this.safeStringLower (order, 'side');
+ if (side === '1') {
+ side = 'buy';
+ } else if (side === '1') {
+ side = 'sell';
+ }
+ let type = this.safeStringLower (order, 'ordType');
+ if (type === '1') {
+ type = 'market';
+ } else if (type === '2') {
+ type = 'limit';
+ } else if (type === '3') {
+ type = 'stop';
+ } else if (type === '4') {
+ type = 'stop-limit';
+ }
+ if (cost === undefined) {
+ if ((price !== undefined) && (filled !== undefined)) {
+ cost = price * filled;
+ }
+ }
+ return {
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'info': order,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': undefined,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': undefined,
+ 'trades': undefined,
+ };
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const orderTypes = {
+ 'market': '1',
+ 'limit': '2',
+ 'stop': '3',
+ 'stop-limit': '4',
+ };
+ const orderType = this.safeString (orderTypes, type);
+ if (orderType === undefined) {
+ throw new InvalidOrder (this.id + ' createOrder does not support order type ' + type + ', supported order types are market, limit, stop, stop-limit');
+ }
+ const orderSides = {
+ 'buy': '1',
+ 'sell': '2',
+ };
+ const orderSide = this.safeString (orderSides, side);
+ if (orderSide === undefined) {
+ throw new InvalidOrder (this.id + ' createOrder does not support order side ' + side + ', supported order sides are buy, sell');
+ }
+ const market = this.market (symbol);
+ const request = {
+ 'account': parseInt (accountId),
+ 'symbol': market['id'],
+ 'ordType': orderType,
+ 'side': orderSide,
+ 'orderQty': this.amountToPrecision (symbol, amount),
+ 'transactTime': this.milliseconds () * 1000000,
+ // 'clOrdId': this.uuid (), // required
+ // 'price': this.priceToPrecision (symbol, price), // required for limit and stop-limit orders
+ // 'stopPx': this.priceToPrecision (symbol, stopPx), // required for stop and stop-limit orders
+ // 'timeInForce': '1', // default '1' = GoodTillCancelled, '3' = ImmediateOrCancel, '4' = FillOrKill
+ // 'execInst': '0',
+ // '0' = StayOnOfferSide, maker only, reject instead of aggressive execution
+ // '9' = PegToOfferSide, maker only, best available level instead of aggressive execution
+ // 'o' = CancelOnConnectionLoss
+ // 'positionID': 1013838923, // required when positionEffect == 'C' with hedged accounting
+ // 'positionEffect': 'O', // 'C' = Close, 'O' = Open, send C along with the positionID if the order must close a position with hedged accounting mode
+ // 'text': 'comment', // optional
+ // 'grpID': 'group-identifier', // group identifier for cancel on disconnect orders
+ };
+ if ((type === 'limit') || (type === 'stop-limit')) {
+ if (price === undefined) {
+ throw new InvalidOrder (this.id + ' createOrder requires a price argument for order type ' + type);
+ }
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ if ((type === 'stop') || (type === 'stop-limit')) {
+ const stopPx = this.safeFloat (params, 'stopPx');
+ if (stopPx === undefined) {
+ throw new InvalidOrder (this.id + ' createOrder requires a stopPx param for order type ' + type);
+ }
+ request['stopPx'] = this.priceToPrecision (symbol, stopPx);
+ params = this.omit (params, 'stopPx');
+ }
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'clOrdId', this.uuid ());
+ if (clientOrderId !== undefined) {
+ request['clOrdId'] = clientOrderId;
+ params = this.omit (params, [ 'clientOrderId', 'clOrdId' ]);
+ }
+ const response = await this.privatePostTradingOrderNew (this.extend (request, params));
+ //
+ // {
+ // "msgType":"8",
+ // "account":1012838720,
+ // "clOrdId":"XAq0pRQ1g",
+ // "orderId":"64d7a06a-27e5-422e-99d9-3cadc04f5a35",
+ // "symbol":"XBTUSD",
+ // "ordType":"2",
+ // "price":"9000",
+ // "transactTime":1593778763271127920,
+ // "execId":"ff5fb8153652f0516bf07b6979255bed053c84b9",
+ // "execType":"I",
+ // "ordStatus":"0",
+ // "side":"1",
+ // "orderQty":"1",
+ // "leavesQty":"1",
+ // "cumQty":"0",
+ // "positionEffect":"O",
+ // "marginAmt":"0.00000556",
+ // "marginAmtType":"11"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const market = this.market (symbol);
+ const request = {
+ 'account': parseInt (accountId),
+ 'clOrdId': this.uuid (),
+ 'symbol': market['id'],
+ 'transactTime': this.milliseconds () * 1000000,
+ // 'origClOrdId': this.uuid (), // one of orderId or origClOrdId is required
+ // 'orderId': id,
+ // 'side': '1', // 1 = buy, 2 = sell
+ // 'execInst': '0',
+ // '0' = StayOnOfferSide, maker only, reject instead of aggressive execution
+ // '9' = PegToOfferSide, maker only, best available level instead of aggressive execution
+ // 'o' = CancelOnConnectionLoss
+ // 'orderQty': 38 M decimal
+ // 'price': this.priceToPrecision (symbol, price), // required for limit and stop-limit orders
+ // 'stopPx': this.priceToPrecision (symbol, stopPx), // required for stop and stop-limit orders
+ // 'capPrice': this.priceToPrecision (symbol, capPrice), // the price beyond which the order will not move for trailing stop and attempt-zero-loss
+ // 'pegPriceType': '8', // '8' = TrailingStopPeg, identifies a trailing stop or an attempt-zero-loss order
+ // 'pegOffsetType': '2', // '2' = BasisPoints, the unit of the distance to the stop price for a trailing stop or an attempt-zero-loss order
+ // 'pegOffsetValue': 123, // distance to the trailing stop or attempt-zero-loss
+ };
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'origClOrdId');
+ if (clientOrderId !== undefined) {
+ request['origClOrdId'] = clientOrderId;
+ params = this.omit (params, [ 'clientOrderId', 'origClOrdId' ]);
+ } else {
+ request['orderId'] = id;
+ }
+ if (amount !== undefined) {
+ request['orderQty'] = this.amountToPrecision (symbol, amount);
+ }
+ if (price !== undefined) {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ const stopPx = this.safeFloat (params, 'stopPx');
+ if (stopPx !== undefined) {
+ request['stopPx'] = this.priceToPrecision (symbol, stopPx);
+ params = this.omit (params, 'stopPx');
+ }
+ const capPrice = this.safeFloat (params, 'capPrice');
+ if (capPrice !== undefined) {
+ request['capPrice'] = this.priceToPrecision (symbol, capPrice);
+ params = this.omit (params, 'capPrice');
+ }
+ const response = await this.privatePostTradingOrderReplace (this.extend (request, params));
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'origClOrdId');
+ params = this.omit (params, [ 'clientOrderId', 'origClOrdId' ]);
+ const market = this.market (symbol);
+ const request = {
+ 'account': parseInt (accountId),
+ 'symbol': market['id'],
+ 'clOrdId': this.uuid (),
+ 'transactTime': this.milliseconds () * 1000000,
+ };
+ if (clientOrderId !== undefined) {
+ request['origClOrdId'] = clientOrderId;
+ } else {
+ request['orderId'] = id;
+ }
+ const response = await this.privatePostTradingOrderCancel (this.extend (request, params));
+ //
+ // {
+ // "msgType":"8",
+ // "account":1012838158,
+ // "clOrdId":"0fa3fb55-9dc0-4cfc-a1db-6aa8b7dd2d98",
+ // "origClOrdId":"3b2878bb-24d8-4922-9d2a-5b8009416677",
+ // "orderId":"665b418e-9d09-4461-b733-d317f6bff43f",
+ // "symbol":"ETHUSD",
+ // "ordType":"2",
+ // "price":"640",
+ // "transactTime":1595060080941618739,
+ // "execId":"c541c0ca437c0e6501c3a50a9d4dc8f575f49972",
+ // "execType":"6",
+ // "ordStatus":"6",
+ // "side":"2",
+ // "orderQty":"1",
+ // "leavesQty":"0",
+ // "cumQty":"0",
+ // "positionEffect":"O",
+ // "marginAmt":"0.000032",
+ // "marginAmtType":"11"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const request = {
+ 'account': parseInt (accountId),
+ 'clOrdId': this.uuid (),
+ // 'side': '1', // 1 = buy, 2 = sell, optional filter, cancel only orders with the given side
+ // 'positionEffect': 'C', // C = Close, O = Open, optional filter, cancel only orders with the given positionEffect, applicable only for accounts with hedged accounting
+ };
+ if (symbol !== undefined) {
+ const market = this.market (symbol);
+ request['symbol'] = market['id'];
+ request['massCancelRequestType'] = '1'; // CancelOrdersForASecurity
+ } else {
+ request['massCancelRequestType'] = '7'; // CancelAllOrders
+ }
+ const response = await this.privatePostTradingOrderMassCancel (this.extend (request, params));
+ //
+ // {
+ // "msgType":"r",
+ // "clOrdId":"b3e95759-e43e-4b3a-b664-a4d213e281a7",
+ // "massActionReportID":"e915b6f4-a7ca-4c5c-b8d6-e39862530248",
+ // "massCancelResponse":"1",
+ // "symbol":"ETHUSD",
+ // "transactTime":1595065630133756426,
+ // "totalAffectedOrders":2,
+ // "account":1012838158
+ // }
+ //
+ return response;
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const request = {
+ 'accountId': accountId,
+ // 'symbol': market['id'],
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ const response = await this.privateGetTradingAccountsAccountIdActiveOrders (this.extend (request, params));
+ //
+ // [
+ // {
+ // "msgType":"8",
+ // "account":1012838720,
+ // "clOrdId":"XAq0pRQ1g",
+ // "orderId":"64d7a06a-27e5-422e-99d9-3cadc04f5a35",
+ // "symbol":"XBTUSD",
+ // "ordType":"2",
+ // "price":"9000",
+ // "transactTime":1593778763271127920,
+ // "execId":"ff5fb8153652f0516bf07b6979255bed053c84b9",
+ // "execType":"I",
+ // "ordStatus":"0",
+ // "side":"1",
+ // "orderQty":"1",
+ // "leavesQty":"1",
+ // "cumQty":"0",
+ // "positionEffect":"O",
+ // "marginAmt":"0.00000556",
+ // "marginAmtType":"11"
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const request = {
+ 'accountId': accountId,
+ // 'from': this.iso8601 (since) * 1000000,
+ // 'to': this.iso8601 (this.milliseconds ()) * 1000000, // max range is 7 days
+ // 'symbol': market['id'],
+ // 'limit': 100,
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['from'] = this.iso8601 (since) * 1000000;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetTradingAccountsAccountIdLastOrderStatuses (this.extend (request, params));
+ //
+ // [
+ // {
+ // "msgType":"8",
+ // "account":1012838720,
+ // "clOrdId":"XAq0pRQ1g",
+ // "orderId":"64d7a06a-27e5-422e-99d9-3cadc04f5a35",
+ // "symbol":"XBTUSD",
+ // "ordType":"2",
+ // "price":"9000",
+ // "transactTime":1593778763271127920,
+ // "execId":"ff5fb8153652f0516bf07b6979255bed053c84b9",
+ // "execType":"I",
+ // "ordStatus":"0",
+ // "side":"1",
+ // "orderQty":"1",
+ // "leavesQty":"1",
+ // "cumQty":"0",
+ // "positionEffect":"O",
+ // "marginAmt":"0.00000556",
+ // "marginAmtType":"11"
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async createDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const currency = this.currency (code);
+ const request = {
+ 'accountId': accountId,
+ 'currency': currency['id'],
+ };
+ const response = await this.privatePostTransfersAccountsAccountIdDepositAddressCurrency (this.extend (request, params));
+ //
+ // {
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
+ // "uri": "bitcoin:mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9?message=Xena Exchange",
+ // "allowsRenewal": true
+ // }
+ //
+ const address = this.safeValue (response, 'address');
+ const tag = undefined;
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': response,
+ };
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const currency = this.currency (code);
+ const request = {
+ 'accountId': accountId,
+ 'currency': currency['id'],
+ };
+ const response = await this.privateGetTransfersAccountsAccountIdDepositAddressCurrency (this.extend (request, params));
+ //
+ // {
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
+ // "uri": "bitcoin:mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9?message=Xena Exchange",
+ // "allowsRenewal": true
+ // }
+ //
+ const address = this.safeValue (response, 'address');
+ const tag = undefined;
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': response,
+ };
+ }
+
+ async fetchTransactionsByType (type, code = undefined, since = undefined, limit = undefined, params = {}) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchTransactions() requires a currency `code` argument');
+ }
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ 'accountId': accountId,
+ };
+ if (since !== undefined) {
+ request['since'] = parseInt (since / 1000);
+ }
+ const method = 'privateGetTransfersAccountsAccountId' + this.capitalize (type);
+ const response = await this[method] (this.extend (request, params));
+ //
+ // {
+ // "withdrawals": [
+ // {
+ // "withdrawalRequestId": 47383243,
+ // "externalId": "...", // external ID submitted by the client when creating the request
+ // "status": 1,
+ // "statusMessage": "Pending confirmation",
+ // "amount": "10.2",
+ // "currency": "BTC",
+ // "lastUpdated": ,
+ // "blockchain": "Bitcoin",
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
+ // "txId": "0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98"
+ // }
+ // ]
+ // }
+ //
+ // {
+ // "deposits": [
+ // {
+ // "currency": "BTC",
+ // "amount": "1.2",
+ // "status": 1,
+ // "statusMessage": "Processing",
+ // "blockchain": "Bitcoin",
+ // "txId": "0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98",
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
+ // "lastUpdated":
+ // "confirmations": 2,
+ // "requiredConfirmations": 6
+ // }
+ // ]
+ // }
+ //
+ //
+ const transactions = this.safeValue (response, type, []);
+ return this.parseTransactions (transactions, currency, since, limit);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsByType ('withdrawals', code, since, limit, params);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsByType ('deposits', code, since, limit, params);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // withdraw()
+ //
+ // {
+ // "withdrawalRequestId": 47383243,
+ // "status": 1,
+ // "statusMessage": "Pending confirmation"
+ // }
+ //
+ // fetchWithdrawals
+ //
+ // {
+ // "withdrawalRequestId": 47383243,
+ // "externalId": "...", // external ID submitted by the client when creating the request
+ // "status": 1,
+ // "statusMessage": "Pending confirmation",
+ // "amount": "10.2",
+ // "currency": "BTC",
+ // "lastUpdated": ,
+ // "blockchain": "Bitcoin",
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
+ // "txId": "0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98"
+ // }
+ //
+ // fetchDeposits
+ //
+ // {
+ // "currency": "BTC",
+ // "amount": "1.2",
+ // "status": 1,
+ // "statusMessage": "Processing",
+ // "blockchain": "Bitcoin",
+ // "txId": "0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98",
+ // "address": "mu5GceHFAG38mGRYCFqafe5ZiNKLX3rKk9",
+ // "lastUpdated":
+ // "confirmations": 2,
+ // "requiredConfirmations": 6
+ // }
+ //
+ const id = this.safeString (transaction, 'withdrawalRequestId');
+ const type = (id === undefined) ? 'deposit' : 'withdrawal';
+ let updated = this.safeInteger (transaction, 'lastUpdated');
+ if (updated !== undefined) {
+ updated = parseInt (updated / 1000000);
+ }
+ const timestamp = undefined;
+ const txid = this.safeString (transaction, 'txId');
+ const currencyId = this.safeString (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const address = this.safeString (transaction, 'address');
+ const addressFrom = undefined;
+ const addressTo = address;
+ const amount = this.safeFloat (transaction, 'amount');
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const fee = undefined;
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'addressFrom': addressFrom,
+ 'addressTo': addressTo,
+ 'address': address,
+ 'tagFrom': undefined,
+ 'tagTo': undefined,
+ 'tag': undefined,
+ 'type': type,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': updated,
+ 'fee': fee,
+ };
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ '1': 'pending', // new
+ '2': 'ok', // completed
+ '3': 'failed', // duplicate
+ '4': 'failed', // not enough money
+ '5': 'pending', // waiting for manual approval from XENA
+ '100': 'pending', // request is being processed
+ '101': 'pending', // request is being processed
+ '102': 'pending', // request is being processed
+ '103': 'pending', // request is being processed
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const currency = this.currency (code);
+ let uuid = this.uuid ();
+ uuid = uuid.split ('-');
+ uuid = uuid.join ('');
+ const request = {
+ 'currency': currency['id'],
+ 'accountId': accountId,
+ 'amount': this.currencyToPrecision (code, amount),
+ 'address': address,
+ 'id': uuid, // mandatory external ID (string), used by the client to identify his request
+ };
+ const response = await this.privatePostTransfersAccountsAccountIdWithdrawals (this.extend (request, params));
+ //
+ // {
+ // "withdrawalRequestId": 47383243,
+ // "status": 1,
+ // "statusMessage": "Pending confirmation"
+ // }
+ //
+ return this.parseTransaction (response, currency);
+ }
+
+ parseLedgerEntryType (type) {
+ const types = {
+ 'deposit': 'transaction',
+ 'withdrawal': 'transaction',
+ 'internal deposit': 'transfer',
+ 'internal withdrawal': 'transfer',
+ 'rebate': 'rebate',
+ 'reward': 'reward',
+ };
+ return this.safeString (types, type, type);
+ }
+
+ parseLedgerEntry (item, currency = undefined) {
+ //
+ // {
+ // "accountId":8263118,
+ // "ts":1551974415000000000,
+ // "amount":"-1",
+ // "currency":"BTC",
+ // "kind":"internal withdrawal",
+ // "commission":"0",
+ // "id":96
+ // }
+ //
+ const id = this.safeString (item, 'id');
+ let direction = undefined;
+ const account = this.safeString (item, 'accountId');
+ const referenceId = undefined;
+ const referenceAccount = undefined;
+ const type = this.parseLedgerEntryType (this.safeString (item, 'kind'));
+ const code = this.safeCurrencyCode (this.safeString (item, 'currency'), currency);
+ let amount = this.safeFloat (item, 'amount');
+ if (amount < 0) {
+ direction = 'out';
+ amount = Math.abs (amount);
+ } else {
+ direction = 'in';
+ }
+ let timestamp = this.safeInteger (item, 'ts');
+ if (timestamp !== undefined) {
+ timestamp = parseInt (timestamp / 1000000);
+ }
+ const fee = {
+ 'cost': this.safeFloat (item, 'commission'),
+ 'currency': code,
+ };
+ const before = undefined;
+ const after = this.safeFloat (item, 'balance');
+ 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': fee,
+ };
+ }
+
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountId = await this.getAccountId (params);
+ const request = {
+ 'accountId': accountId,
+ // 'page': 1,
+ // 'limit': 5000, // max 5000
+ // 'from': time,
+ // 'to': time,
+ // 'symbol': currency['id'],
+ // 'trade_id': id,
+ // 'client_order_id': id,
+ // 'txid': txid,
+ // 'kind': 'deposit', // 'withdrawal, 'internal deposit', 'internal withdrawal', 'rebate', 'reward'
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['symbol'] = currency['id'];
+ }
+ if (since !== undefined) {
+ request['from'] = since * 1000000;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // max 5000
+ }
+ const response = await this.privateGetTransfersAccountsAccountIdBalanceHistory (this.extend (request, params));
+ //
+ // [
+ // {
+ // "accountId":8263118,
+ // "ts":1551974415000000000,
+ // "amount":"-1",
+ // "currency":"BTC",
+ // "kind":"internal withdrawal",
+ // "commission":"0",
+ // "id":96
+ // },
+ // {
+ // "accountId":8263118,
+ // "ts":1551964677000000000,
+ // "amount":"-1",
+ // "currency":"BTC",
+ // "kind":"internal deposit",
+ // "commission":"0",
+ // "id":95
+ // }
+ // ]
+ //
+ return this.parseLedger (response, currency, since, limit);
+ }
+
+ nonce () {
+ return this.milliseconds ();
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let url = this.urls['api'][api] + '/' + this.implodeParams (path, params);
+ const query = this.omit (params, this.extractParams (path));
+ if (api === 'public') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (api === 'private') {
+ this.checkRequiredCredentials ();
+ let nonce = this.nonce ();
+ // php does not format it properly
+ // therefore we use string concatenation here
+ // nonce *= 1000000;
+ nonce = nonce.toString ();
+ nonce = nonce + '000000'; // see the comment a few lines above
+ const payload = 'AUTH' + nonce;
+ const secret = this.secret.slice (14, 78);
+ const ecdsa = this.ecdsa (payload, secret, 'p256', 'sha256');
+ const signature = ecdsa['r'] + ecdsa['s'];
+ headers = {
+ 'X-AUTH-API-KEY': this.apiKey,
+ 'X-AUTH-API-PAYLOAD': payload,
+ 'X-AUTH-API-SIGNATURE': signature,
+ 'X-AUTH-API-NONCE': nonce,
+ };
+ if (method === 'GET') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (method === 'POST') {
+ body = this.json (query);
+ headers['Content-Type'] = 'application/json';
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return;
+ }
+ //
+ // {"error":"Validation failed","fields":["address"]}
+ // {"error":"Money not enough. You have only: 0 ETH","fields":["amount"]}
+ //
+ if (code >= 400) {
+ const feedback = this.id + ' ' + this.json (response);
+ const message = this.safeString (response, 'error');
+ const exact = this.exceptions['exact'];
+ if (message in exact) {
+ throw new exact[message] (feedback);
+ }
+ const broad = this.exceptions['broad'];
+ const broadKey = this.findBroadlyMatchedKey (broad, body);
+ if (broadKey !== undefined) {
+ throw new broad[broadKey] (feedback);
+ }
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
+
+},{"./base/Exchange":5,"./base/errors":7}],177:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InvalidNonce, InsufficientFunds, OrderNotFound, DDoSProtection, InvalidOrder, AuthenticationError } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InvalidNonce, InsufficientFunds, OrderNotFound, DDoSProtection, InvalidOrder, AuthenticationError, RateLimitExceeded } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -111879,18 +135172,23 @@ module.exports = class yobit extends Exchange {
'rateLimit': 3000, // responses are cached every 2 seconds
'version': '3',
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createDepositAddress': true,
'createMarketOrder': false,
- 'fetchClosedOrders': 'emulated',
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchDepositAddress': true,
'fetchDeposits': false,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
'fetchOrderBooks': true,
- 'fetchOrders': 'emulated',
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTransactions': false,
'fetchWithdrawals': false,
'withdraw': true,
@@ -111946,16 +135244,19 @@ module.exports = class yobit extends Exchange {
'ATM': 'Autumncoin',
'BCC': 'BCH',
'BCS': 'BitcoinStake',
+ 'BITS': 'Bitstar',
'BLN': 'Bulleon',
'BOT': 'BOTcoin',
'BON': 'BONES',
'BPC': 'BitcoinPremium',
'BTS': 'Bitshares2',
'CAT': 'BitClave',
+ 'CBC': 'CryptoBossCoin',
'CMT': 'CometCoin',
'COV': 'Coven Coin',
'COVX': 'COV',
'CPC': 'Capricoin',
+ 'CREDIT': 'Creditbit',
'CS': 'CryptoSpots',
'DCT': 'Discount',
'DFT': 'DraftCoin',
@@ -111996,7 +135297,7 @@ module.exports = class yobit extends Exchange {
'PLAY': 'PlayCoin',
'PIVX': 'Darknet',
'PRS': 'PRE',
- 'PUTIN': 'PUT',
+ 'PUTIN': 'PutinCoin',
'STK': 'StakeCoin',
'SUB': 'Subscriptio',
'PAY': 'EPAY',
@@ -112005,7 +135306,11 @@ module.exports = class yobit extends Exchange {
'REP': 'Republicoin',
'RUR': 'RUB',
'TTC': 'TittieCoin',
+ 'UNI': 'Universe',
+ 'UST': 'Uservice',
+ 'VOL': 'VolumeCoin',
'XIN': 'XINCoin',
+ 'XRA': 'Ratecoin',
},
'options': {
// 'fetchTickersMaxLength': 2048,
@@ -112036,11 +135341,15 @@ module.exports = class yobit extends Exchange {
'data unavailable': ExchangeNotAvailable,
'external service unavailable': ExchangeNotAvailable,
'Total transaction amount': InvalidOrder, // { "success": 0, "error": "Total transaction amount is less than minimal total: 0.00010000"}
+ 'The given order has already been closed and cannot be cancelled': InvalidOrder,
'Insufficient funds': InsufficientFunds,
'invalid key': AuthenticationError,
'invalid nonce': InvalidNonce, // {"success":0,"error":"invalid nonce (has already been used)"}'
+ 'Total order amount is less than minimal amount': InvalidOrder,
+ 'Rate Limited': RateLimitExceeded,
},
},
+ 'orders': {}, // orders cache / emulation
});
}
@@ -112185,11 +135494,7 @@ module.exports = class yobit extends Exchange {
ids = Object.keys (response);
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- let symbol = id;
- if (id in this.markets_by_id) {
- const market = this.markets_by_id[id];
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (id);
result[symbol] = this.parseOrderBook (response[id]);
}
return result;
@@ -112261,15 +135566,11 @@ module.exports = class yobit extends Exchange {
for (let k = 0; k < keys.length; k++) {
const id = keys[k];
const ticker = tickers[id];
- let symbol = id;
- let market = undefined;
- if (id in this.markets_by_id) {
- market = this.markets_by_id[id];
- symbol = market['symbol'];
- }
+ const market = this.safeMarket (id);
+ const symbol = market['symbol'];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -112288,17 +135589,10 @@ module.exports = class yobit extends Exchange {
const price = this.safeFloat2 (trade, 'rate', 'price');
const id = this.safeString2 (trade, 'trade_id', 'tid');
const order = this.safeString (trade, 'order_id');
- if ('pair' in trade) {
- const marketId = this.safeString (trade, 'pair');
- market = this.safeValue (this.markets_by_id, marketId, market);
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (trade, 'pair');
+ const symbol = this.safeSymbol (marketId, market);
const amount = this.safeFloat (trade, 'amount');
const type = 'limit'; // all trades are still limit trades
- let takerOrMaker = undefined;
let fee = undefined;
const feeCost = this.safeFloat (trade, 'commission');
if (feeCost !== undefined) {
@@ -112311,12 +135605,8 @@ module.exports = class yobit extends Exchange {
}
const isYourOrder = this.safeValue (trade, 'is_your_order');
if (isYourOrder !== undefined) {
- takerOrMaker = 'taker';
- if (isYourOrder) {
- takerOrMaker = 'maker';
- }
if (fee === undefined) {
- fee = this.calculateFee (symbol, type, side, amount, price, takerOrMaker);
+ fee = this.calculateFee (symbol, type, side, amount, price, 'taker');
}
}
let cost = undefined;
@@ -112333,7 +135623,7 @@ module.exports = class yobit extends Exchange {
'symbol': symbol,
'type': type,
'side': side,
- 'takerOrMaker': takerOrMaker,
+ 'takerOrMaker': undefined,
'price': price,
'amount': amount,
'cost': cost,
@@ -112390,7 +135680,7 @@ module.exports = class yobit extends Exchange {
remaining = this.safeFloat (response['return'], 'remains', amount);
}
const timestamp = this.milliseconds ();
- const order = {
+ return {
'id': id,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
@@ -112411,8 +135701,6 @@ module.exports = class yobit extends Exchange {
'average': undefined,
'trades': undefined,
};
- this.orders[id] = order;
- return order;
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -112420,11 +135708,7 @@ module.exports = class yobit extends Exchange {
const request = {
'order_id': parseInt (id),
};
- const response = await this.privatePostCancelOrder (this.extend (request, params));
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- }
- return response;
+ return await this.privatePostCancelOrder (this.extend (request, params));
}
parseOrderStatus (status) {
@@ -112441,31 +135725,16 @@ module.exports = class yobit extends Exchange {
const id = this.safeString (order, 'id');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
const timestamp = this.safeTimestamp (order, 'timestamp_created');
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'pair');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'pair');
+ const symbol = this.safeSymbol (marketId, market);
const remaining = this.safeFloat (order, 'amount');
- let amount = undefined;
+ const amount = this.safeFloat (order, 'start_amount');
const price = this.safeFloat (order, 'rate');
let filled = undefined;
let cost = undefined;
- if ('start_amount' in order) {
- amount = this.safeFloat (order, 'start_amount');
- } else {
- if (id in this.orders) {
- amount = this.orders[id]['amount'];
- }
- }
if (amount !== undefined) {
if (remaining !== undefined) {
- filled = amount - remaining;
+ filled = Math.max (0, amount - remaining);
cost = price * filled;
}
}
@@ -112481,8 +135750,10 @@ module.exports = class yobit extends Exchange {
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'remaining': remaining,
@@ -112495,21 +135766,6 @@ module.exports = class yobit extends Exchange {
return result;
}
- parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
- const result = [];
- const ids = Object.keys (orders);
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- for (let i = 0; i < ids.length; i++) {
- const id = ids[i];
- const order = this.extend ({ 'id': id }, orders[id]);
- result.push (this.extend (this.parseOrder (order, market), params));
- }
- return this.filterBySymbolSinceLimit (result, symbol, since, limit);
- }
-
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const request = {
@@ -112517,57 +135773,13 @@ module.exports = class yobit extends Exchange {
};
const response = await this.privatePostOrderInfo (this.extend (request, params));
id = id.toString ();
- const newOrder = this.parseOrder (this.extend ({ 'id': id }, response['return'][id]));
- const oldOrder = (id in this.orders) ? this.orders[id] : {};
- this.orders[id] = this.extend (oldOrder, newOrder);
- return this.orders[id];
+ const orders = this.safeValue (response, 'return', {});
+ return this.parseOrder (this.extend ({ 'id': id }, orders[id]));
}
- updateCachedOrders (openOrders, symbol) {
- // update local cache with open orders
- // this will add unseen orders and overwrite existing ones
- for (let j = 0; j < openOrders.length; j++) {
- const id = openOrders[j]['id'];
- this.orders[id] = openOrders[j];
- }
- const openOrdersIndexedById = this.indexBy (openOrders, 'id');
- const cachedOrderIds = Object.keys (this.orders);
- for (let k = 0; k < cachedOrderIds.length; k++) {
- // match each cached order to an order in the open orders array
- // possible reasons why a cached order may be missing in the open orders array:
- // - order was closed or canceled -> update cache
- // - symbol mismatch (e.g. cached BTC/USDT, fetched ETH/USDT) -> skip
- const cachedOrderId = cachedOrderIds[k];
- let cachedOrder = this.orders[cachedOrderId];
- if (!(cachedOrderId in openOrdersIndexedById)) {
- // cached order is not in open orders array
- // if we fetched orders by symbol and it doesn't match the cached order -> won't update the cached order
- if (symbol !== undefined && symbol !== cachedOrder['symbol']) {
- continue;
- }
- // cached order is absent from the list of open orders -> mark the cached order as closed
- if (cachedOrder['status'] === 'open') {
- cachedOrder = this.extend (cachedOrder, {
- 'status': 'closed', // likewise it might have been canceled externally (unnoticed by "us")
- 'cost': undefined,
- 'filled': cachedOrder['amount'],
- 'remaining': 0.0,
- });
- if (cachedOrder['cost'] === undefined) {
- if (cachedOrder['filled'] !== undefined) {
- cachedOrder['cost'] = cachedOrder['filled'] * cachedOrder['price'];
- }
- }
- this.orders[cachedOrderId] = cachedOrder;
- }
- }
- }
- return this.toArray (this.orders);
- }
-
- async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument');
+ throw new ArgumentsRequired (this.id + ' fetchOpenOrders() requires a symbol argument');
}
await this.loadMarkets ();
const request = {};
@@ -112577,24 +135789,8 @@ module.exports = class yobit extends Exchange {
request['pair'] = market['id'];
}
const response = await this.privatePostActiveOrders (this.extend (request, params));
- // can only return 'open' orders (i.e. no way to fetch 'closed' orders)
- let openOrders = [];
- if ('return' in response) {
- openOrders = this.parseOrders (response['return'], market);
- }
- const allOrders = this.updateCachedOrders (openOrders, symbol);
- const result = this.filterBySymbol (allOrders, symbol);
- return this.filterBySinceLimit (result, since, limit);
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const orders = await this.fetchOrders (symbol, since, limit, params);
- return this.filterBy (orders, 'status', 'open');
- }
-
- async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const orders = await this.fetchOrders (symbol, since, limit, params);
- return this.filterBy (orders, 'status', 'closed');
+ const orders = this.safeValue (response, 'return', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -112796,7 +135992,7 @@ module.exports = class yobit extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],171:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],178:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -112815,10 +136011,17 @@ module.exports = class zaif extends Exchange {
'rateLimit': 2000,
'version': '1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createMarketOrder': false,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchMarkets': true,
+ 'fetchOrderBook': true,
+ 'fetchOpenOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'urls': {
@@ -113053,16 +136256,8 @@ module.exports = class zaif extends Exchange {
cost = amount * price;
}
}
- if (market === undefined) {
- const marketId = this.safeString (trade, 'currency_pair');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (trade, 'currency_pair');
+ const symbol = this.safeSymbol (marketId, market, '_');
return {
'id': id,
'info': trade,
@@ -113136,12 +136331,8 @@ module.exports = class zaif extends Exchange {
let side = this.safeString (order, 'action');
side = (side === 'bid') ? 'buy' : 'sell';
const timestamp = this.safeTimestamp (order, 'timestamp');
- if (!market) {
- const marketId = this.safeString (order, 'currency_pair');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
+ const marketId = this.safeString (order, 'currency_pair');
+ const symbol = this.safeSymbol (marketId, market, '_');
const price = this.safeFloat (order, 'price');
const amount = this.safeFloat (order, 'amount');
let cost = undefined;
@@ -113151,10 +136342,6 @@ module.exports = class zaif extends Exchange {
}
}
const id = this.safeString (order, 'id');
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
return {
'id': id,
'clientOrderId': undefined,
@@ -113164,34 +136351,21 @@ module.exports = class zaif extends Exchange {
'status': 'open',
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': undefined,
'remaining': undefined,
'trades': undefined,
'fee': undefined,
- 'info': undefined,
+ 'info': order,
'average': undefined,
};
}
- parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
- const result = [];
- const ids = Object.keys (orders);
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- for (let i = 0; i < ids.length; i++) {
- const id = ids[i];
- const order = this.extend ({ 'id': id }, orders[id]);
- result.push (this.extend (this.parseOrder (order, market), params));
- }
- return this.filterBySymbolSinceLimit (result, symbol, since, limit);
- }
-
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
let market = undefined;
@@ -113308,7 +136482,7 @@ module.exports = class zaif extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],172:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],179:[function(require,module,exports){
'use strict';
// ---------------------------------------------------------------------------
@@ -113327,14 +136501,21 @@ module.exports = class zb extends Exchange {
'rateLimit': 1000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchDepositAddress': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'fetchMarkets': true,
'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'timeframes': {
@@ -113376,6 +136557,8 @@ module.exports = class zb extends Exchange {
'3006': AuthenticationError, // 'Invalid IP or inconsistent with the bound IP',
'3007': AuthenticationError, // 'The request time has expired',
'3008': OrderNotFound, // 'Transaction records not found',
+ '3009': InvalidOrder, // 'The price exceeds the limit',
+ '3011': InvalidOrder, // 'The entrusted price is abnormal, please modify it and place order again',
'4001': ExchangeNotAvailable, // 'API interface is locked or not enabled',
'4002': DDoSProtection, // 'Request too often',
},
@@ -113601,7 +136784,7 @@ module.exports = class zb extends Exchange {
const market = anotherMarketsById[ids[i]];
result[market['symbol']] = this.parseTicker (response[ids[i]], market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -113842,15 +137025,8 @@ module.exports = class zb extends Exchange {
if (createDateField in order) {
timestamp = order[createDateField];
}
- let symbol = undefined;
const marketId = this.safeString (order, 'currency');
- if (marketId in this.markets_by_id) {
- // get symbol from currency
- market = this.marketsById[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const price = this.safeFloat (order, 'price');
const filled = this.safeFloat (order, 'trade_amount');
const amount = this.safeFloat (order, 'total_amount');
@@ -113876,8 +137052,10 @@ module.exports = class zb extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'average': average,
'cost': cost,
'amount': amount,
@@ -113959,7 +137137,7 @@ module.exports = class zb extends Exchange {
}
};
-},{"./base/Exchange":7,"./base/errors":9}],173:[function(require,module,exports){
+},{"./base/Exchange":5,"./base/errors":7}],180:[function(require,module,exports){
(function (global){
'use strict';
@@ -114453,7 +137631,7 @@ var objectKeys = Object.keys || function (obj) {
};
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"util/":231}],174:[function(require,module,exports){
+},{"util/":238}],181:[function(require,module,exports){
'use strict'
exports.byteLength = byteLength
@@ -114569,9 +137747,9 @@ function fromByteArray (uint8) {
return parts.join('')
}
-},{}],175:[function(require,module,exports){
+},{}],182:[function(require,module,exports){
-},{}],176:[function(require,module,exports){
+},{}],183:[function(require,module,exports){
(function (process,Buffer){
'use strict';
/* eslint camelcase: "off" */
@@ -114983,7 +138161,7 @@ Zlib.prototype._reset = function () {
exports.Zlib = Zlib;
}).call(this,require('_process'),require("buffer").Buffer)
-},{"_process":200,"assert":173,"buffer":178,"pako/lib/zlib/constants":190,"pako/lib/zlib/deflate.js":192,"pako/lib/zlib/inflate.js":194,"pako/lib/zlib/zstream":198}],177:[function(require,module,exports){
+},{"_process":207,"assert":180,"buffer":185,"pako/lib/zlib/constants":197,"pako/lib/zlib/deflate.js":199,"pako/lib/zlib/inflate.js":201,"pako/lib/zlib/zstream":205}],184:[function(require,module,exports){
(function (process){
'use strict';
@@ -115595,7 +138773,7 @@ util.inherits(DeflateRaw, Zlib);
util.inherits(InflateRaw, Zlib);
util.inherits(Unzip, Zlib);
}).call(this,require('_process'))
-},{"./binding":176,"_process":200,"assert":173,"buffer":178,"stream":219,"util":231}],178:[function(require,module,exports){
+},{"./binding":183,"_process":207,"assert":180,"buffer":185,"stream":226,"util":238}],185:[function(require,module,exports){
/*!
* The buffer module from node.js, for the browser.
*
@@ -117311,7 +140489,7 @@ function numberIsNaN (obj) {
return obj !== obj // eslint-disable-line no-self-compare
}
-},{"base64-js":174,"ieee754":184}],179:[function(require,module,exports){
+},{"base64-js":181,"ieee754":191}],186:[function(require,module,exports){
module.exports = {
"100": "Continue",
"101": "Switching Protocols",
@@ -117377,7 +140555,7 @@ module.exports = {
"511": "Network Authentication Required"
}
-},{}],180:[function(require,module,exports){
+},{}],187:[function(require,module,exports){
module.exports={
"O_RDONLY": 0,
"O_WRONLY": 1,
@@ -117588,7 +140766,7 @@ module.exports={
"UV_UDP_REUSEADDR": 4
}
-},{}],181:[function(require,module,exports){
+},{}],188:[function(require,module,exports){
(function (Buffer){
// Copyright Joyent, Inc. and other Node contributors.
//
@@ -117699,7 +140877,7 @@ function objectToString(o) {
}
}).call(this,{"isBuffer":require("../../is-buffer/index.js")})
-},{"../../is-buffer/index.js":186}],182:[function(require,module,exports){
+},{"../../is-buffer/index.js":193}],189:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -118003,7 +141181,7 @@ function isUndefined(arg) {
return arg === void 0;
}
-},{}],183:[function(require,module,exports){
+},{}],190:[function(require,module,exports){
var http = require('http')
var url = require('url')
@@ -118036,7 +141214,7 @@ function validateParams (params) {
return params
}
-},{"http":220,"url":226}],184:[function(require,module,exports){
+},{"http":227,"url":233}],191:[function(require,module,exports){
exports.read = function (buffer, offset, isLE, mLen, nBytes) {
var e, m
var eLen = nBytes * 8 - mLen - 1
@@ -118122,7 +141300,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) {
buffer[offset + i - d] |= s * 128
}
-},{}],185:[function(require,module,exports){
+},{}],192:[function(require,module,exports){
if (typeof Object.create === 'function') {
// implementation from standard node.js 'util' module
module.exports = function inherits(ctor, superCtor) {
@@ -118147,7 +141325,7 @@ if (typeof Object.create === 'function') {
}
}
-},{}],186:[function(require,module,exports){
+},{}],193:[function(require,module,exports){
/*!
* Determine if an object is a Buffer
*
@@ -118170,14 +141348,14 @@ function isSlowBuffer (obj) {
return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0))
}
-},{}],187:[function(require,module,exports){
+},{}],194:[function(require,module,exports){
var toString = {}.toString;
module.exports = Array.isArray || function (arr) {
return toString.call(arr) == '[object Array]';
};
-},{}],188:[function(require,module,exports){
+},{}],195:[function(require,module,exports){
'use strict';
@@ -118284,7 +141462,7 @@ exports.setTyped = function (on) {
exports.setTyped(TYPED_OK);
-},{}],189:[function(require,module,exports){
+},{}],196:[function(require,module,exports){
'use strict';
// Note: adler32 takes 12% for level 0 and 2% for level 6.
@@ -118337,7 +141515,7 @@ function adler32(adler, buf, len, pos) {
module.exports = adler32;
-},{}],190:[function(require,module,exports){
+},{}],197:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -118407,7 +141585,7 @@ module.exports = {
//Z_NULL: null // Use -1 or null inline, depending on var type
};
-},{}],191:[function(require,module,exports){
+},{}],198:[function(require,module,exports){
'use strict';
// Note: we can't get significant speed boost here.
@@ -118468,7 +141646,7 @@ function crc32(crc, buf, len, pos) {
module.exports = crc32;
-},{}],192:[function(require,module,exports){
+},{}],199:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -120344,7 +143522,7 @@ exports.deflatePrime = deflatePrime;
exports.deflateTune = deflateTune;
*/
-},{"../utils/common":188,"./adler32":189,"./crc32":191,"./messages":196,"./trees":197}],193:[function(require,module,exports){
+},{"../utils/common":195,"./adler32":196,"./crc32":198,"./messages":203,"./trees":204}],200:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -120691,7 +143869,7 @@ module.exports = function inflate_fast(strm, start) {
return;
};
-},{}],194:[function(require,module,exports){
+},{}],201:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -122249,7 +145427,7 @@ exports.inflateSyncPoint = inflateSyncPoint;
exports.inflateUndermine = inflateUndermine;
*/
-},{"../utils/common":188,"./adler32":189,"./crc32":191,"./inffast":193,"./inftrees":195}],195:[function(require,module,exports){
+},{"../utils/common":195,"./adler32":196,"./crc32":198,"./inffast":200,"./inftrees":202}],202:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -122594,7 +145772,7 @@ module.exports = function inflate_table(type, lens, lens_index, codes, table, ta
return 0;
};
-},{"../utils/common":188}],196:[function(require,module,exports){
+},{"../utils/common":195}],203:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -122628,7 +145806,7 @@ module.exports = {
'-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
};
-},{}],197:[function(require,module,exports){
+},{}],204:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -123850,7 +147028,7 @@ exports._tr_flush_block = _tr_flush_block;
exports._tr_tally = _tr_tally;
exports._tr_align = _tr_align;
-},{"../utils/common":188}],198:[function(require,module,exports){
+},{"../utils/common":195}],205:[function(require,module,exports){
'use strict';
// (C) 1995-2013 Jean-loup Gailly and Mark Adler
@@ -123899,7 +147077,7 @@ function ZStream() {
module.exports = ZStream;
-},{}],199:[function(require,module,exports){
+},{}],206:[function(require,module,exports){
(function (process){
'use strict';
@@ -123946,7 +147124,7 @@ function nextTick(fn, arg1, arg2, arg3) {
}
}).call(this,require('_process'))
-},{"_process":200}],200:[function(require,module,exports){
+},{"_process":207}],207:[function(require,module,exports){
// shim for using process in browser
var process = module.exports = {};
@@ -124132,7 +147310,7 @@ process.chdir = function (dir) {
};
process.umask = function() { return 0; };
-},{}],201:[function(require,module,exports){
+},{}],208:[function(require,module,exports){
(function (global){
/*! https://mths.be/punycode v1.4.1 by @mathias */
;(function(root) {
@@ -124669,7 +147847,7 @@ process.umask = function() { return 0; };
}(this));
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],202:[function(require,module,exports){
+},{}],209:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -124755,7 +147933,7 @@ var isArray = Array.isArray || function (xs) {
return Object.prototype.toString.call(xs) === '[object Array]';
};
-},{}],203:[function(require,module,exports){
+},{}],210:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -124842,16 +148020,16 @@ var objectKeys = Object.keys || function (obj) {
return res;
};
-},{}],204:[function(require,module,exports){
+},{}],211:[function(require,module,exports){
'use strict';
exports.decode = exports.parse = require('./decode');
exports.encode = exports.stringify = require('./encode');
-},{"./decode":202,"./encode":203}],205:[function(require,module,exports){
+},{"./decode":209,"./encode":210}],212:[function(require,module,exports){
module.exports = require('./lib/_stream_duplex.js');
-},{"./lib/_stream_duplex.js":206}],206:[function(require,module,exports){
+},{"./lib/_stream_duplex.js":213}],213:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -124976,7 +148154,7 @@ function forEach(xs, f) {
f(xs[i], i);
}
}
-},{"./_stream_readable":208,"./_stream_writable":210,"core-util-is":181,"inherits":185,"process-nextick-args":199}],207:[function(require,module,exports){
+},{"./_stream_readable":215,"./_stream_writable":217,"core-util-is":188,"inherits":192,"process-nextick-args":206}],214:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -125024,7 +148202,7 @@ function PassThrough(options) {
PassThrough.prototype._transform = function (chunk, encoding, cb) {
cb(null, chunk);
};
-},{"./_stream_transform":209,"core-util-is":181,"inherits":185}],208:[function(require,module,exports){
+},{"./_stream_transform":216,"core-util-is":188,"inherits":192}],215:[function(require,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
@@ -126034,7 +149212,7 @@ function indexOf(xs, x) {
return -1;
}
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./_stream_duplex":206,"./internal/streams/BufferList":211,"./internal/streams/destroy":212,"./internal/streams/stream":213,"_process":200,"core-util-is":181,"events":182,"inherits":185,"isarray":187,"process-nextick-args":199,"safe-buffer":218,"string_decoder/":224,"util":175}],209:[function(require,module,exports){
+},{"./_stream_duplex":213,"./internal/streams/BufferList":218,"./internal/streams/destroy":219,"./internal/streams/stream":220,"_process":207,"core-util-is":188,"events":189,"inherits":192,"isarray":194,"process-nextick-args":206,"safe-buffer":225,"string_decoder/":231,"util":182}],216:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -126249,7 +149427,7 @@ function done(stream, er, data) {
return stream.push(null);
}
-},{"./_stream_duplex":206,"core-util-is":181,"inherits":185}],210:[function(require,module,exports){
+},{"./_stream_duplex":213,"core-util-is":188,"inherits":192}],217:[function(require,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
@@ -126916,7 +150094,7 @@ Writable.prototype._destroy = function (err, cb) {
cb(err);
};
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./_stream_duplex":206,"./internal/streams/destroy":212,"./internal/streams/stream":213,"_process":200,"core-util-is":181,"inherits":185,"process-nextick-args":199,"safe-buffer":218,"util-deprecate":228}],211:[function(require,module,exports){
+},{"./_stream_duplex":213,"./internal/streams/destroy":219,"./internal/streams/stream":220,"_process":207,"core-util-is":188,"inherits":192,"process-nextick-args":206,"safe-buffer":225,"util-deprecate":235}],218:[function(require,module,exports){
'use strict';
/**/
@@ -126991,7 +150169,7 @@ module.exports = function () {
return BufferList;
}();
-},{"safe-buffer":218}],212:[function(require,module,exports){
+},{"safe-buffer":225}],219:[function(require,module,exports){
'use strict';
/**/
@@ -127064,13 +150242,13 @@ module.exports = {
destroy: destroy,
undestroy: undestroy
};
-},{"process-nextick-args":199}],213:[function(require,module,exports){
+},{"process-nextick-args":206}],220:[function(require,module,exports){
module.exports = require('events').EventEmitter;
-},{"events":182}],214:[function(require,module,exports){
+},{"events":189}],221:[function(require,module,exports){
module.exports = require('./readable').PassThrough
-},{"./readable":215}],215:[function(require,module,exports){
+},{"./readable":222}],222:[function(require,module,exports){
exports = module.exports = require('./lib/_stream_readable.js');
exports.Stream = exports;
exports.Readable = exports;
@@ -127079,13 +150257,13 @@ exports.Duplex = require('./lib/_stream_duplex.js');
exports.Transform = require('./lib/_stream_transform.js');
exports.PassThrough = require('./lib/_stream_passthrough.js');
-},{"./lib/_stream_duplex.js":206,"./lib/_stream_passthrough.js":207,"./lib/_stream_readable.js":208,"./lib/_stream_transform.js":209,"./lib/_stream_writable.js":210}],216:[function(require,module,exports){
+},{"./lib/_stream_duplex.js":213,"./lib/_stream_passthrough.js":214,"./lib/_stream_readable.js":215,"./lib/_stream_transform.js":216,"./lib/_stream_writable.js":217}],223:[function(require,module,exports){
module.exports = require('./readable').Transform
-},{"./readable":215}],217:[function(require,module,exports){
+},{"./readable":222}],224:[function(require,module,exports){
module.exports = require('./lib/_stream_writable.js');
-},{"./lib/_stream_writable.js":210}],218:[function(require,module,exports){
+},{"./lib/_stream_writable.js":217}],225:[function(require,module,exports){
/* eslint-disable node/no-deprecated-api */
var buffer = require('buffer')
var Buffer = buffer.Buffer
@@ -127149,7 +150327,7 @@ SafeBuffer.allocUnsafeSlow = function (size) {
return buffer.SlowBuffer(size)
}
-},{"buffer":178}],219:[function(require,module,exports){
+},{"buffer":185}],226:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -127278,7 +150456,7 @@ Stream.prototype.pipe = function(dest, options) {
return dest;
};
-},{"events":182,"inherits":185,"readable-stream/duplex.js":205,"readable-stream/passthrough.js":214,"readable-stream/readable.js":215,"readable-stream/transform.js":216,"readable-stream/writable.js":217}],220:[function(require,module,exports){
+},{"events":189,"inherits":192,"readable-stream/duplex.js":212,"readable-stream/passthrough.js":221,"readable-stream/readable.js":222,"readable-stream/transform.js":223,"readable-stream/writable.js":224}],227:[function(require,module,exports){
(function (global){
var ClientRequest = require('./lib/request')
var extend = require('xtend')
@@ -127360,7 +150538,7 @@ http.METHODS = [
'UNSUBSCRIBE'
]
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./lib/request":222,"builtin-status-codes":179,"url":226,"xtend":232}],221:[function(require,module,exports){
+},{"./lib/request":229,"builtin-status-codes":186,"url":233,"xtend":239}],228:[function(require,module,exports){
(function (global){
exports.fetch = isFunction(global.fetch) && isFunction(global.ReadableStream)
@@ -127433,7 +150611,7 @@ function isFunction (value) {
xhr = null // Help gc
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],222:[function(require,module,exports){
+},{}],229:[function(require,module,exports){
(function (process,global,Buffer){
var capability = require('./capability')
var inherits = require('inherits')
@@ -127743,7 +150921,7 @@ var unsafeHeaders = [
]
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
-},{"./capability":221,"./response":223,"_process":200,"buffer":178,"inherits":185,"readable-stream":215,"to-arraybuffer":225}],223:[function(require,module,exports){
+},{"./capability":228,"./response":230,"_process":207,"buffer":185,"inherits":192,"readable-stream":222,"to-arraybuffer":232}],230:[function(require,module,exports){
(function (process,global,Buffer){
var capability = require('./capability')
var inherits = require('inherits')
@@ -127929,7 +151107,7 @@ IncomingMessage.prototype._onXHRProgress = function () {
}
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("buffer").Buffer)
-},{"./capability":221,"_process":200,"buffer":178,"inherits":185,"readable-stream":215}],224:[function(require,module,exports){
+},{"./capability":228,"_process":207,"buffer":185,"inherits":192,"readable-stream":222}],231:[function(require,module,exports){
'use strict';
var Buffer = require('safe-buffer').Buffer;
@@ -128202,7 +151380,7 @@ function simpleWrite(buf) {
function simpleEnd(buf) {
return buf && buf.length ? this.write(buf) : '';
}
-},{"safe-buffer":218}],225:[function(require,module,exports){
+},{"safe-buffer":225}],232:[function(require,module,exports){
var Buffer = require('buffer').Buffer
module.exports = function (buf) {
@@ -128231,7 +151409,7 @@ module.exports = function (buf) {
}
}
-},{"buffer":178}],226:[function(require,module,exports){
+},{"buffer":185}],233:[function(require,module,exports){
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
@@ -128965,7 +152143,7 @@ Url.prototype.parseHost = function() {
if (host) this.hostname = host;
};
-},{"./util":227,"punycode":201,"querystring":204}],227:[function(require,module,exports){
+},{"./util":234,"punycode":208,"querystring":211}],234:[function(require,module,exports){
'use strict';
module.exports = {
@@ -128983,7 +152161,7 @@ module.exports = {
}
};
-},{}],228:[function(require,module,exports){
+},{}],235:[function(require,module,exports){
(function (global){
/**
@@ -129054,16 +152232,16 @@ function config (name) {
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{}],229:[function(require,module,exports){
-arguments[4][185][0].apply(exports,arguments)
-},{"dup":185}],230:[function(require,module,exports){
+},{}],236:[function(require,module,exports){
+arguments[4][192][0].apply(exports,arguments)
+},{"dup":192}],237:[function(require,module,exports){
module.exports = function isBuffer(arg) {
return arg && typeof arg === 'object'
&& typeof arg.copy === 'function'
&& typeof arg.fill === 'function'
&& typeof arg.readUInt8 === 'function';
}
-},{}],231:[function(require,module,exports){
+},{}],238:[function(require,module,exports){
(function (process,global){
// Copyright Joyent, Inc. and other Node contributors.
//
@@ -129653,7 +152831,7 @@ function hasOwnProperty(obj, prop) {
}
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
-},{"./support/isBuffer":230,"_process":200,"inherits":229}],232:[function(require,module,exports){
+},{"./support/isBuffer":237,"_process":207,"inherits":236}],239:[function(require,module,exports){
module.exports = extend
var hasOwnProperty = Object.prototype.hasOwnProperty;
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/.eslintrc b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/.eslintrc
new file mode 100644
index 000000000..4a873d0f0
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/.eslintrc
@@ -0,0 +1,84 @@
+{
+ "env": {
+ "node": true
+ },
+ "parserOptions": {
+ "ecmaVersion": 2017,
+ "sourceType": "script"
+ },
+ "extends": ["eslint:recommended", "airbnb-base"],
+ "rules": {
+ "strict": "off",
+ "semi": "error",
+ "indent": ["error", 4],
+ "init-declarations": "error",
+ "no-undef-init": "off",
+ "comma-dangle": ["error", {
+ "arrays": "always-multiline",
+ "objects": "always-multiline",
+ "imports": "always-multiline",
+ "exports": "always-multiline",
+ "functions": "never"
+ }],
+ "brace-style": ["error", "1tbs"],
+ "multiline-comment-style": ["error", "separate-lines"],
+ "dot-notation": "off",
+ "quote-props": ["error", "always"],
+ "no-multi-spaces": ["error", { "ignoreEOLComments": true }],
+ "no-whitespace-before-property": "error",
+ "space-before-blocks": ["error", "always"],
+ "space-before-function-paren": ["error", "always"],
+ "no-spaced-func": "off",
+ "func-call-spacing": ["error", "always"],
+ "block-spacing": ["error", "always"],
+ "keyword-spacing": ["error", { "before": true, "after": true }],
+ "object-curly-spacing": ["error", "always", { "objectsInObjects": false }],
+ "object-curly-newline": ["error", { "consistent": true }],
+ "space-infix-ops": "error",
+ "space-unary-ops": "error",
+ "space-in-parens": "error",
+ "no-nested-ternary": "error",
+ "eqeqeq": "error",
+ "quotes": ["error", "single", { "avoidEscape": true }],
+ "no-unused-vars": ["error", { "argsIgnorePattern": "^(symbol|price|tag|since|limit|params|market|timeframe|api|path|code|currency|response|requestHeaders|requestBody|bidsKey|asksKey)" }],
+ "new-parens": "error",
+ "new-cap": ["error"],
+ "no-var": "error",
+ "prefer-const": ["error", {
+ "destructuring": "any",
+ "ignoreReadBeforeAssign": false
+ }],
+ "no-warning-comments": ["warn", { "terms": ["fixme"] }],
+ "padded-blocks": ["error", "never"],
+ "lines-between-class-members": "error",
+ "no-multiple-empty-lines": ["error", { "max": 1 }],
+ "padding-line-between-statements": ["error",
+ { "blankLine": "never", "prev":"*", "next": "*" },
+ { "blankLine": "always", "prev":"directive", "next": "*" },
+ { "blankLine": "always", "prev":"*", "next": "cjs-export" }
+ ],
+ "prefer-template": "off",
+ "curly": "error",
+ "no-plusplus": "off",
+ "no-restricted-properties": "off",
+ "prefer-destructuring": "off",
+ "class-methods-use-this": "off",
+ "no-param-reassign": "off",
+ "max-len": "off",
+ "no-return-await": "off",
+ "array-bracket-spacing": "off",
+ "radix": "off",
+ "camelcase": "off",
+ "no-lonely-if": "off",
+ "no-mixed-operators": "off",
+ "no-shadow": "off",
+ "no-useless-concat": "off",
+ "no-continue": "off",
+ "no-else-return": "off",
+ "no-unneeded-ternary": "off",
+ "operator-assignment": "off",
+ "no-underscore-dangle": "off",
+ "consistent-return": "off",
+ "no-await-in-loop": "off"
+ }
+}
diff --git a/TaskServer/node_modules/ccxt/js/acx.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/acx.js
similarity index 94%
rename from TaskServer/node_modules/ccxt/js/acx.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/acx.js
index d1b31388a..011921fa4 100644
--- a/TaskServer/node_modules/ccxt/js/acx.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/acx.js
@@ -16,11 +16,19 @@ module.exports = class acx extends Exchange {
'rateLimit': 1000,
'version': 'v2',
'has': {
+ 'cancelOrder': true,
'CORS': true,
- 'fetchTickers': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchOHLCV': true,
- 'withdraw': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1',
@@ -227,7 +235,7 @@ module.exports = class acx extends Exchange {
}
result[symbol] = this.parseTicker (response[id], market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -264,6 +272,14 @@ module.exports = class acx extends Exchange {
};
}
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTimestamp (params);
+ //
+ // 1594911427
+ //
+ return response * 1000;
+ }
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -274,14 +290,14 @@ module.exports = class acx extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
return [
- ohlcv[0] * 1000,
- ohlcv[1],
- ohlcv[2],
- ohlcv[3],
- ohlcv[4],
- ohlcv[5],
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -313,13 +329,8 @@ module.exports = class acx extends Exchange {
}
parseOrder (order, market = undefined) {
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- } else {
- const marketId = this.safeString (order, 'market');
- symbol = this.markets_by_id[marketId]['symbol'];
- }
+ const marketId = this.safeString (order, 'market');
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const status = this.parseOrderStatus (this.safeString (order, 'state'));
const type = this.safeString (order, 'type');
@@ -334,8 +345,10 @@ module.exports = class acx extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': this.safeFloat (order, 'price'),
+ 'stopPrice': undefined,
'amount': this.safeFloat (order, 'volume'),
'filled': this.safeFloat (order, 'executed_volume'),
'remaining': this.safeFloat (order, 'remaining_volume'),
diff --git a/TaskServer/node_modules/ccxt/js/aofex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/aofex.js
similarity index 95%
rename from TaskServer/node_modules/ccxt/js/aofex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/aofex.js
index 779d280c7..fb5e7f4a3 100644
--- a/TaskServer/node_modules/ccxt/js/aofex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/aofex.js
@@ -227,7 +227,7 @@ module.exports = class aofex extends Exchange {
return result;
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// id: 1584950100,
@@ -297,7 +297,7 @@ module.exports = class aofex extends Exchange {
//
const result = this.safeValue (response, 'result', {});
const data = this.safeValue (result, 'data', []);
- return this.parseOHLCVs (data, market, timeframe, since, limit);
+ return this.parseOHLCVs (data, market, since, limit);
}
async fetchBalance (params = {}) {
@@ -422,13 +422,9 @@ module.exports = class aofex extends Exchange {
const percentage = change / open * 100;
const baseVolume = this.safeFloat (ticker, 'amount');
const quoteVolume = this.safeFloat (ticker, 'vol');
- let vwap = undefined;
- if (quoteVolume !== undefined) {
- if (baseVolume !== undefined) {
- if (baseVolume > 0) {
- vwap = parseFloat (this.priceToPrecision (symbol, quoteVolume / baseVolume));
- }
- }
+ let vwap = this.vwap (baseVolume, quoteVolume);
+ if (vwap !== undefined) {
+ vwap = parseFloat (this.priceToPrecision (symbol, vwap));
}
return {
'symbol': symbol,
@@ -487,23 +483,10 @@ module.exports = class aofex extends Exchange {
const result = {};
for (let i = 0; i < tickers.length; i++) {
const marketId = this.safeString (tickers[i], 'symbol');
- let market = undefined;
- let symbol = marketId;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
+ const market = this.safeMarket (marketId, undefined, '-');
+ const symbol = market['symbol'];
const data = this.safeValue (tickers[i], 'data', {});
- const ticker = this.parseTicker (data, market);
- ticker['symbol'] = symbol;
- result[symbol] = ticker;
+ result[symbol] = this.parseTicker (data, market);
}
return this.filterByArray (result, 'symbol', symbols);
}
@@ -707,26 +690,12 @@ module.exports = class aofex extends Exchange {
const id = this.safeString (order, 'order_sn');
const orderStatus = this.safeString (order, 'status');
const status = this.parseOrderStatus (orderStatus);
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- let base = undefined;
- let quote = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- base = this.safeCurrencyCode (baseId);
- quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ market = this.safeMarket (marketId, market, '-');
+ let timestamp = this.parse8601 (this.safeString (order, 'ctime'));
+ if (timestamp !== undefined) {
+ timestamp -= 28800000; // 8 hours, adjust to UTC
}
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- base = market['base'];
- quote = market['quote'];
- }
- const timestamp = this.parse8601 (this.safeString (order, 'ctime')) - 28800000; // 8 hours, adjust to UTC
const orderType = this.safeString (order, 'type');
const type = (orderType === '2') ? 'limit' : 'market';
const side = this.safeString (order, 'side');
@@ -790,7 +759,7 @@ module.exports = class aofex extends Exchange {
}
}
if (feeCost !== undefined) {
- const feeCurrencyCode = (side === 'buy') ? base : quote;
+ const feeCurrencyCode = (side === 'buy') ? market['base'] : market['quote'];
fee = {
'cost': feeCost,
'currency': feeCurrencyCode,
@@ -826,10 +795,12 @@ module.exports = class aofex extends Exchange {
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
'status': status,
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
diff --git a/TaskServer/node_modules/ccxt/js/base/.eslintrc.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/.eslintrc.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/base/.eslintrc.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/.eslintrc.js
diff --git a/TaskServer/node_modules/ccxt/js/base/Exchange.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/Exchange.js
similarity index 76%
rename from TaskServer/node_modules/ccxt/js/base/Exchange.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/Exchange.js
index f818dd8a6..f231581ed 100644
--- a/TaskServer/node_modules/ccxt/js/base/Exchange.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/Exchange.js
@@ -30,7 +30,7 @@ const {
, defaultFetch
} = functions
-const {
+const { // eslint-disable-line object-curly-newline
ExchangeError
, BadSymbol
, InvalidAddress
@@ -41,26 +41,10 @@ const {
, ExchangeNotAvailable
, RateLimitExceeded } = require ('./errors')
-const { TRUNCATE, ROUND, DECIMAL_PLACES } = functions.precisionConstants
+const { TRUNCATE, ROUND, DECIMAL_PLACES, NO_PADDING } = functions.precisionConstants
const BN = require ('../static_dependencies/BN/bn')
-// ----------------------------------------------------------------------------
-// web3 / 0x imports
-
-let ethAbi = undefined
- , ethUtil = undefined
-
-try {
- const requireFunction = require;
- ethAbi = requireFunction ('ethereumjs-abi') // eslint-disable-line global-require
- ethUtil = requireFunction ('ethereumjs-util') // eslint-disable-line global-require
- // we prefer bignumber.js over BN.js
- // BN = requireFunction ('bn.js') // eslint-disable-line global-require
-} catch (e) {
- // nothing
-}
-
// ----------------------------------------------------------------------------
module.exports = class Exchange {
@@ -75,6 +59,7 @@ module.exports = class Exchange {
'certified': false,
'pro': false,
'has': {
+ 'loadMarkets': true,
'cancelAllOrders': false,
'cancelOrder': true,
'cancelOrders': false,
@@ -115,6 +100,7 @@ module.exports = class Exchange {
'fetchWithdrawals': false,
'privateAPI': true,
'publicAPI': true,
+ 'signIn': false,
'withdraw': false,
},
'urls': {
@@ -198,6 +184,7 @@ module.exports = class Exchange {
'BCHSV': 'BSV',
},
'precisionMode': DECIMAL_PLACES,
+ 'paddingMode': NO_PADDING,
'limits': {
'amount': { 'min': undefined, 'max': undefined },
'price': { 'min': undefined, 'max': undefined },
@@ -259,12 +246,14 @@ module.exports = class Exchange {
this.balance = {}
this.orderbooks = {}
this.tickers = {}
- this.orders = {}
+ this.orders = undefined
this.trades = {}
this.transactions = {}
this.ohlcvs = {}
+ this.myTrades = undefined
this.requiresWeb3 = false
+ this.requiresEddsa = false
this.precision = {}
this.enableLastJsonResponse = true
@@ -276,7 +265,9 @@ module.exports = class Exchange {
const unCamelCaseProperties = (obj = this) => {
if (obj !== null) {
- for (const k of Object.getOwnPropertyNames (obj)) {
+ const ownPropertyNames = Object.getOwnPropertyNames (obj)
+ for (let i = 0; i < ownPropertyNames.length; i++) {
+ const k = ownPropertyNames[i]
this[unCamelCase (k)] = this[k]
}
unCamelCaseProperties (Object.getPrototypeOf (obj))
@@ -284,24 +275,33 @@ module.exports = class Exchange {
}
unCamelCaseProperties ()
- // merge configs
- const config = deepExtend (this.describe (), userConfig)
-
// merge to this
- for (const [property, value] of Object.entries (config)) {
- this[property] = deepExtend (this[property], value)
+ const configEntries = Object.entries (this.describe ()).concat (Object.entries (userConfig))
+ for (let i = 0; i < configEntries.length; i++) {
+ const [property, value] = configEntries[i]
+ if (value && Object.getPrototypeOf (value) === Object.prototype) {
+ this[property] = deepExtend (this[property], value)
+ } else {
+ this[property] = value
+ }
}
- if (!this.httpAgent) {
- this.httpAgent = defaultFetch.http ? new defaultFetch.http.Agent ({ 'keepAlive': true }) : undefined
+ const agentOptions = {
+ 'keepAlive': true,
}
- if (!this.httpsAgent) {
- this.httpsAgent = defaultFetch.https ? new defaultFetch.https.Agent ({ 'keepAlive': true }) : undefined
+ if (!this.httpAgent && defaultFetch.http && isNode) {
+ this.httpAgent = new defaultFetch.http.Agent (agentOptions)
+ }
+
+ if (!this.httpsAgent && defaultFetch.https && isNode) {
+ this.httpsAgent = new defaultFetch.https.Agent (agentOptions)
}
// generate old metainfo interface
- for (const k in this.has) {
+ const hasKeys = Object.keys (this.has)
+ for (let i = 0; i < hasKeys.length; i++) {
+ const k = hasKeys[i]
this['has' + capitalize (k)] = !!this.has[k] // converts 'emulated' to true
}
@@ -381,7 +381,6 @@ module.exports = class Exchange {
const params = { method, headers, body, timeout: this.timeout }
if (this.agent) {
- this.agent.keepAlive = true
params['agent'] = this.agent
} else if (this.httpAgent && url.indexOf ('http://') === 0) {
params['agent'] = this.httpAgent
@@ -430,46 +429,31 @@ module.exports = class Exchange {
}
}
- defineRestApi (api, methodName, options = {}) {
-
- for (const type of Object.keys (api)) {
- for (const httpMethod of Object.keys (api[type])) {
-
- let paths = api[type][httpMethod]
- for (let i = 0; i < paths.length; i++) {
- let path = paths[i].trim ()
- let splitPath = path.split (/[^a-zA-Z0-9]/)
-
- let uppercaseMethod = httpMethod.toUpperCase ()
- let lowercaseMethod = httpMethod.toLowerCase ()
- let camelcaseMethod = this.capitalize (lowercaseMethod)
- let camelcaseSuffix = splitPath.map (this.capitalize).join ('')
- let underscoreSuffix = splitPath.map (x => x.trim ().toLowerCase ()).filter (x => x.length > 0).join ('_')
-
- let camelcase = type + camelcaseMethod + this.capitalize (camelcaseSuffix)
- let underscore = type + '_' + lowercaseMethod + '_' + underscoreSuffix
-
- if ('suffixes' in options) {
- if ('camelcase' in options['suffixes']) {
- camelcase += options['suffixes']['camelcase']
- }
- if ('underscore' in options.suffixes) {
- underscore += options['suffixes']['underscore']
- }
- }
-
- if ('underscore_suffix' in options) {
- underscore += options.underscoreSuffix;
- }
- if ('camelcase_suffix' in options) {
- camelcase += options.camelcaseSuffix;
- }
-
- let partial = async params => this[methodName] (path, type, uppercaseMethod, params || {})
-
+ defineRestApi (api, methodName, paths = []) {
+ const keys = Object.keys (api)
+ for (let i = 0; i < keys.length; i++) {
+ const key = keys[i]
+ const value = api[key]
+ if (Array.isArray (value)) {
+ const uppercaseMethod = key.toUpperCase ()
+ const lowercaseMethod = key.toLowerCase ()
+ const camelcaseMethod = this.capitalize (lowercaseMethod)
+ for (let k = 0; k < value.length; k++) {
+ const path = value[k].trim ()
+ const splitPath = path.split (/[^a-zA-Z0-9]/)
+ const camelcaseSuffix = splitPath.map (this.capitalize).join ('')
+ const underscoreSuffix = splitPath.map ((x) => x.trim ().toLowerCase ()).filter ((x) => x.length > 0).join ('_')
+ const camelcasePrefix = [ paths[0] ].concat (paths.slice (1).map (this.capitalize)).join ('')
+ const underscorePrefix = [ paths[0] ].concat (paths.slice (1).map ((x) => x.trim ()).filter ((x) => x.length > 0)).join ('_')
+ const camelcase = camelcasePrefix + camelcaseMethod + this.capitalize (camelcaseSuffix)
+ const underscore = underscorePrefix + '_' + lowercaseMethod + '_' + underscoreSuffix
+ const typeArgument = (paths.length > 1) ? paths : paths[0]
+ const partial = async (params) => this[methodName] (path, typeArgument, uppercaseMethod, params || {})
this[camelcase] = partial
this[underscore] = partial
}
+ } else {
+ this.defineRestApi (value, methodName, paths.concat ([ key ]))
}
}
}
@@ -478,6 +462,10 @@ module.exports = class Exchange {
console.log (... args)
}
+ setHeaders (headers) {
+ return headers;
+ }
+
fetch (url, method = 'GET', headers = undefined, body = undefined) {
if (isNode && this.userAgent) {
@@ -505,6 +493,7 @@ module.exports = class Exchange {
}
headers = extend (this.headers, headers)
+ headers = this.setHeaders (headers)
if (this.verbose) {
this.print ("fetch:\n", this.id, method, url, "\nRequest:\n", headers, "\n", body, "\n")
@@ -567,39 +556,11 @@ module.exports = class Exchange {
// override me
}
- defaultErrorHandler (code, reason, url, method, headers, body, response) {
- if ((code >= 200) && (code <= 299)) {
- return
- }
- let details = body
+ handleHttpStatusCode (code, reason, url, method, body) {
const codeAsString = code.toString ()
- let ErrorClass = undefined
if (codeAsString in this.httpExceptions) {
- ErrorClass = this.httpExceptions[codeAsString]
- }
- if (response === undefined) {
- const maintenance = body.match (/offline|busy|retry|wait|unavailable|maintain|maintenance|maintenancing/i)
- const ddosProtection = body.match (/cloudflare|incapsula|overload|ddos/i)
- if (maintenance) {
- ErrorClass = ExchangeNotAvailable
- details += ' offline, on maintenance, or unreachable from this location at the moment'
- }
- if (ddosProtection) {
- ErrorClass = DDoSProtection
- }
- }
- if (ErrorClass === ExchangeNotAvailable) {
- details += ' (possible reasons: ' + [
- 'invalid API keys',
- 'bad or old nonce',
- 'exchange is down or offline',
- 'on maintenance',
- 'DDoS protection',
- 'rate-limiting',
- ].join (', ') + ')'
- }
- if (ErrorClass !== undefined) {
- throw new ErrorClass ([ this.id, method, url, code, reason, details ].join (' '))
+ const ErrorClass = this.httpExceptions[codeAsString]
+ throw new ErrorClass ([ this.id, method, url, code, reason, body ].join (' '))
}
}
@@ -625,11 +586,11 @@ module.exports = class Exchange {
}
if (this.enableLastHttpResponse) {
- this.last_http_response = responseBody // FIXME: for those classes that haven't switched to handleErrors yet
+ this.last_http_response = responseBody
}
if (this.enableLastJsonResponse) {
- this.last_json_response = json // FIXME: for those classes that haven't switched to handleErrors yet
+ this.last_json_response = json
}
if (this.verbose) {
@@ -637,7 +598,7 @@ module.exports = class Exchange {
}
this.handleErrors (response.status, response.statusText, url, method, responseHeaders, responseBody, json, requestHeaders, requestBody)
- this.defaultErrorHandler (response.status, response.statusText, url, method, responseHeaders, responseBody, json)
+ this.handleHttpStatusCode (response.status, response.statusText, url, method, responseBody)
return json || responseBody
})
@@ -657,16 +618,16 @@ module.exports = class Exchange {
this.currencies = deepExtend (currencies, this.currencies)
} else {
let baseCurrencies =
- values.filter (market => 'base' in market)
- .map (market => ({
+ values.filter ((market) => 'base' in market)
+ .map ((market) => ({
id: market.baseId || market.base,
numericId: (market.baseNumericId !== undefined) ? market.baseNumericId : undefined,
code: market.base,
precision: market.precision ? (market.precision.base || market.precision.amount) : 8,
}))
let quoteCurrencies =
- values.filter (market => 'quote' in market)
- .map (market => ({
+ values.filter ((market) => 'quote' in market)
+ .map ((market) => ({
id: market.quoteId || market.quote,
numericId: (market.quoteNumericId !== undefined) ? market.quoteNumericId : undefined,
code: market.quote,
@@ -678,9 +639,9 @@ module.exports = class Exchange {
this.quoteCurrencies = indexBy (quoteCurrencies, 'code')
const allCurrencies = baseCurrencies.concat (quoteCurrencies)
const groupedCurrencies = groupBy (allCurrencies, 'code')
- const currencies = Object.keys (groupedCurrencies).map (code =>
- groupedCurrencies[code].reduce ((previous, current) =>
- ((previous.precision > current.precision) ? previous : current), groupedCurrencies[code][0]))
+ const currencies = Object.keys (groupedCurrencies).map ((code) =>
+ groupedCurrencies[code].reduce ((previous, current) => // eslint-disable-line implicit-arrow-linebreak
+ ((previous.precision > current.precision) ? previous : current), groupedCurrencies[code][0])) // eslint-disable-line implicit-arrow-linebreak
const sortedCurrencies = sortBy (flatten (currencies), 'code')
this.currencies = deepExtend (indexBy (sortedCurrencies, 'code'), this.currencies)
}
@@ -736,22 +697,24 @@ module.exports = class Exchange {
throw new NotSupported (this.id + ' fetchBidsAsks not supported yet')
}
- async fetchOHLCVC (symbol, timeframe = '1m', since = undefined, limits = undefined, params = {}) {
- if (!this.has['fetchTrades'])
+ async fetchOHLCVC (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ if (!this.has['fetchTrades']) {
throw new NotSupported (this.id + ' fetchOHLCV() not supported yet')
+ }
await this.loadMarkets ()
- const trades = await this.fetchTrades (symbol, since, limits, params)
- const ohlcvc = buildOHLCVC (trades, timeframe, since, limits)
+ const trades = await this.fetchTrades (symbol, since, limit, params)
+ const ohlcvc = buildOHLCVC (trades, timeframe, since, limit)
return ohlcvc
}
- async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limits = undefined, params = {}) {
- if (!this.has['fetchTrades'])
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ if (!this.has['fetchTrades']) {
throw new NotSupported (this.id + ' fetchOHLCV() not supported yet')
+ }
await this.loadMarkets ()
- const trades = await this.fetchTrades (symbol, since, limits, params)
- const ohlcvc = buildOHLCVC (trades, timeframe, since, limits)
- return ohlcvc.map (c => c.slice (0, -1))
+ const trades = await this.fetchTrades (symbol, since, limit, params)
+ const ohlcvc = buildOHLCVC (trades, timeframe, since, limit)
+ return ohlcvc.map ((c) => c.slice (0, -1))
}
parseTradingViewOHLCV (ohlcvs, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
@@ -801,16 +764,6 @@ module.exports = class Exchange {
throw new NotSupported (this.id + ' fetchTickers not supported yet')
}
- purgeCachedOrders (before) {
- const orders = Object
- .values (this.orders)
- .filter (order =>
- (order.status === 'open') ||
- (order.timestamp >= before))
- this.orders = indexBy (orders, 'id')
- return this.orders
- }
-
fetchOrder (id, symbol = undefined, params = {}) {
throw new NotSupported (this.id + ' fetchOrder not supported yet');
}
@@ -889,8 +842,9 @@ module.exports = class Exchange {
}
commonCurrencyCode (currency) {
- if (!this.substituteCommonCurrencyCodes)
+ if (!this.substituteCommonCurrencyCodes) {
return currency
+ }
return this.safeString (this.commonCurrencies, currency, currency)
}
@@ -916,22 +870,26 @@ module.exports = class Exchange {
currency (code) {
- if (this.currencies === undefined)
+ if (this.currencies === undefined) {
throw new ExchangeError (this.id + ' currencies not loaded')
+ }
- if ((typeof code === 'string') && (code in this.currencies))
+ if ((typeof code === 'string') && (code in this.currencies)) {
return this.currencies[code]
+ }
throw new ExchangeError (this.id + ' does not have currency code ' + code)
}
market (symbol) {
- if (this.markets === undefined)
+ if (this.markets === undefined) {
throw new ExchangeError (this.id + ' markets not loaded')
+ }
- if ((typeof symbol === 'string') && (symbol in this.markets))
+ if ((typeof symbol === 'string') && (symbol in this.markets)) {
return this.markets[symbol]
+ }
throw new BadSymbol (this.id + ' does not have market symbol ' + symbol)
}
@@ -942,7 +900,7 @@ module.exports = class Exchange {
}
marketIds (symbols) {
- return symbols.map (symbol => this.marketId (symbol));
+ return symbols.map ((symbol) => this.marketId (symbol))
}
symbol (symbol) {
@@ -952,8 +910,9 @@ module.exports = class Exchange {
url (path, params = {}) {
let result = this.implodeParams (path, params);
const query = this.omit (params, this.extractParams (path))
- if (Object.keys (query).length)
+ if (Object.keys (query).length) {
result += '?' + this.urlencode (query)
+ }
return result
}
@@ -964,7 +923,7 @@ module.exports = class Exchange {
}
parseBidsAsks (bidasks, priceKey = 0, amountKey = 1) {
- return Object.values (bidasks || []).map (bidask => this.parseBidAsk (bidask, priceKey, amountKey))
+ return Object.values (bidasks || []).map ((bidask) => this.parseBidAsk (bidask, priceKey, amountKey))
}
async fetchL2OrderBook (symbol, limit = undefined, params = {}) {
@@ -987,33 +946,33 @@ module.exports = class Exchange {
parseBalance (balance) {
- const currencies = Object.keys (this.omit (balance, [ 'info', 'free', 'used', 'total' ]));
+ const codes = Object.keys (this.omit (balance, [ 'info', 'free', 'used', 'total' ]));
balance['free'] = {}
balance['used'] = {}
balance['total'] = {}
- for (const currency of currencies) {
-
- if (balance[currency].total === undefined) {
- if (balance[currency].free !== undefined && balance[currency].used !== undefined) {
- balance[currency].total = this.sum (balance[currency].free, balance[currency].used)
+ for (let i = 0; i < codes.length; i++) {
+ const code = codes[i]
+ if (balance[code].total === undefined) {
+ if (balance[code].free !== undefined && balance[code].used !== undefined) {
+ balance[code].total = this.sum (balance[code].free, balance[code].used)
}
}
- if (balance[currency].free === undefined) {
- if (balance[currency].total !== undefined && balance[currency].used !== undefined) {
- balance[currency].free = this.sum (balance[currency].total, -balance[currency].used)
+ if (balance[code].free === undefined) {
+ if (balance[code].total !== undefined && balance[code].used !== undefined) {
+ balance[code].free = this.sum (balance[code].total, -balance[code].used)
}
}
- if (balance[currency].used === undefined) {
- if (balance[currency].total !== undefined && balance[currency].free !== undefined) {
- balance[currency].used = this.sum (balance[currency].total, -balance[currency].free)
+ if (balance[code].used === undefined) {
+ if (balance[code].total !== undefined && balance[code].free !== undefined) {
+ balance[code].used = this.sum (balance[code].total, -balance[code].free)
}
}
- balance.free[currency] = balance[currency].free
- balance.used[currency] = balance[currency].used
- balance.total[currency] = balance[currency].total
+ balance.free[code] = balance[code].free
+ balance.used[code] = balance[code].used
+ balance.total[code] = balance[code].total
}
return balance
@@ -1089,15 +1048,13 @@ module.exports = class Exchange {
// single-pass filter for both symbol and since
if (valueIsDefined || sinceIsDefined) {
- array = Object.values (array).filter ((entry) =>
+ array = array.filter ((entry) =>
((valueIsDefined ? (entry[field] === value) : true) &&
(sinceIsDefined ? (entry[key] >= since) : true)))
}
if (limit !== undefined && limit !== null) {
- array = ((tail && !sinceIsDefined) ?
- Object.values (array).slice (-limit) :
- Object.values (array).slice (0, limit))
+ array = (tail && !sinceIsDefined) ? array.slice (-limit) : array.slice (0, limit)
}
return array
@@ -1171,36 +1128,95 @@ module.exports = class Exchange {
}
parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
- // this code is commented out temporarily to catch for exchange-specific errors
- // if (!this.isArray (orders)) {
- // throw new ExchangeError (this.id + ' parseOrders expected an array in the orders argument, but got ' + typeof orders);
- // }
- let result = Object.values (orders).map (order => this.extend (this.parseOrder (order, market), params))
+ //
+ // the value of orders is either a dict or a list
+ //
+ // dict
+ //
+ // {
+ // 'id1': { ... },
+ // 'id2': { ... },
+ // 'id3': { ... },
+ // ...
+ // }
+ //
+ // list
+ //
+ // [
+ // { 'id': 'id1', ... },
+ // { 'id': 'id2', ... },
+ // { 'id': 'id3', ... },
+ // ...
+ // ]
+ //
+ let result = Array.isArray (orders) ?
+ Object.values (orders).map ((order) => this.extend (this.parseOrder (order, market), params)) :
+ Object.entries (orders).map (([ id, order ]) => this.extend (this.parseOrder (this.extend ({ 'id': id }, order), market), params))
result = sortBy (result, 'timestamp')
const symbol = (market !== undefined) ? market['symbol'] : undefined
return this.filterBySymbolSinceLimit (result, symbol, since, limit)
}
+ safeCurrency (currencyId, currency = undefined) {
+ if ((currencyId === undefined) && (currency !== undefined)) {
+ return currency
+ }
+ if ((this.currencies_by_id !== undefined) && (currencyId in this.currencies_by_id)) {
+ return this.currencies_by_id[currencyId]
+ }
+ return {
+ 'id': currencyId,
+ 'code': (currencyId === undefined) ? currencyId : this.commonCurrencyCode (currencyId.toUpperCase ()),
+ }
+ }
+
safeCurrencyCode (currencyId, currency = undefined) {
- let code = undefined
- if (currencyId !== undefined) {
- if (this.currencies_by_id !== undefined && currencyId in this.currencies_by_id) {
- code = this.currencies_by_id[currencyId]['code']
- } else {
- code = this.commonCurrencyCode (currencyId.toUpperCase ())
+ currency = this.safeCurrency (currencyId, currency)
+ return currency['code']
+ }
+
+ safeMarket (marketId, market = undefined, delimiter = undefined) {
+ if (marketId !== undefined) {
+ if (this.markets_by_id !== undefined && marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId]
+ } else if (delimiter !== undefined) {
+ const [ baseId, quoteId ] = marketId.split (delimiter)
+ const base = this.safeCurrencyCode (baseId)
+ const quote = this.safeCurrencyCode (quoteId)
+ const symbol = base + '/' + quote
+ return {
+ 'id': marketId,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ }
}
}
- if (code === undefined && currency !== undefined) {
- code = currency['code']
+ if (market !== undefined) {
+ return market
}
- return code
+ return {
+ 'id': marketId,
+ 'symbol': marketId,
+ 'base': undefined,
+ 'quote': undefined,
+ 'baseId': undefined,
+ 'quoteId': undefined,
+ }
+ }
+
+ safeSymbol (marketId, market = undefined, delimiter = undefined) {
+ market = this.safeMarket (marketId, market, delimiter)
+ return market['symbol'];
}
filterBySymbol (array, symbol = undefined) {
- return ((symbol !== undefined) ? array.filter (entry => entry.symbol === symbol) : array)
+ return ((symbol !== undefined) ? array.filter ((entry) => entry.symbol === symbol) : array)
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
return Array.isArray (ohlcv) ? ohlcv.slice (0, 6) : ohlcv
}
@@ -1215,7 +1231,7 @@ module.exports = class Exchange {
if (limit && (result.length >= limit)) {
break;
}
- const ohlcv = this.parseOHLCV (ohlcvs[i], market, timeframe, since, limit)
+ const ohlcv = this.parseOHLCV (ohlcvs[i], market)
if (since && (ohlcv[0] < since)) {
continue
}
@@ -1237,8 +1253,9 @@ module.exports = class Exchange {
}
async editOrder (id, symbol, ...args) {
- if (!this.enableRateLimit)
+ if (!this.enableRateLimit) {
throw new ExchangeError (this.id + ' editOrder() requires enableRateLimit = true')
+ }
await this.cancelOrder (id, symbol);
return this.createOrder (symbol, ...args)
}
@@ -1268,23 +1285,23 @@ module.exports = class Exchange {
}
costToPrecision (symbol, cost) {
- return decimalToPrecision (cost, ROUND, this.markets[symbol].precision.price, this.precisionMode)
+ return decimalToPrecision (cost, ROUND, this.markets[symbol].precision.price, this.precisionMode, this.paddingMode)
}
priceToPrecision (symbol, price) {
- return decimalToPrecision (price, ROUND, this.markets[symbol].precision.price, this.precisionMode)
+ return decimalToPrecision (price, ROUND, this.markets[symbol].precision.price, this.precisionMode, this.paddingMode)
}
amountToPrecision (symbol, amount) {
- return decimalToPrecision (amount, TRUNCATE, this.markets[symbol].precision.amount, this.precisionMode)
+ return decimalToPrecision (amount, TRUNCATE, this.markets[symbol].precision.amount, this.precisionMode, this.paddingMode)
}
feeToPrecision (symbol, fee) {
- return decimalToPrecision (fee, ROUND, this.markets[symbol].precision.price, this.precisionMode)
+ return decimalToPrecision (fee, ROUND, this.markets[symbol].precision.price, this.precisionMode, this.paddingMode)
}
currencyToPrecision (currency, fee) {
- return decimalToPrecision (fee, ROUND, this.currencies[currency]['precision'], this.precisionMode);
+ return decimalToPrecision (fee, ROUND, this.currencies[currency]['precision'], this.precisionMode, this.paddingMode);
}
calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) {
@@ -1299,26 +1316,19 @@ module.exports = class Exchange {
}
}
- // ------------------------------------------------------------------------
- // web3 / 0x methods
- static hasWeb3 () {
- return ethUtil && ethAbi
- }
-
checkRequiredDependencies () {
- if (!Exchange.hasWeb3 ()) {
- throw new ExchangeError ('Required dependencies missing: \nnpm i ethereumjs-util ethereumjs-abi --no-save');
- }
+ return
}
soliditySha3 (array) {
// we only support address, uint256, and string solidity types
const encoded = []
- for (const value of array) {
+ for (let i = 0; i < array.length; i++) {
+ const value = array[i]
if (Number.isInteger (value) || value.match (/^[0-9]+$/)) {
encoded.push (this.numberToBE (this.numberToString (value), 32))
} else {
- const noPrefix = Exchange.remove0xPrefix (value)
+ const noPrefix = this.remove0xPrefix (value)
if (noPrefix.length === 40 && noPrefix.toLowerCase ().match (/^[0-9a-f]+$/)) { // check if it is an address
encoded.push (this.base16ToBinary (noPrefix))
} else {
@@ -1330,108 +1340,7 @@ module.exports = class Exchange {
return '0x' + this.hash (concated, 'keccak', 'hex')
}
- getZeroExOrderHash (order) {
- return this.soliditySha3 ([
- order['exchangeContractAddress'], // address
- order['maker'], // address
- order['taker'], // address
- order['makerTokenAddress'], // address
- order['takerTokenAddress'], // address
- order['feeRecipient'], // address
- order['makerTokenAmount'], // uint256
- order['takerTokenAmount'], // uint256
- order['makerFee'], // uint256
- order['takerFee'], // uint256
- order['expirationUnixTimestampSec'], // uint256
- order['salt'], // uint256
- ]);
- }
-
- getZeroExOrderHashV2 (order) {
- // https://github.com/0xProject/0x-monorepo/blob/development/python-packages/order_utils/src/zero_ex/order_utils/__init__.py
- const addressPadding = '000000000000000000000000';
- const header = '1901';
- const domainStructHeader = '91ab3d17e3a50a9d89e63fd30b92be7f5336b03b287bb946787a83a9d62a2766f0f24618f4c4be1e62e026fb039a20ef96f4495294817d1027ffaa6d1f70e61ead7c5bef027816a800da1736444fb58a807ef4c9603b7848673f7e3a68eb14a5';
- const orderSchemaHash = '770501f88a26ede5c04a20ef877969e961eb11fc13b78aaf414b633da0d4f86f';
-
- const domainStructHash = ethAbi.soliditySHA3 (
- [
- 'bytes',
- 'bytes',
- 'address'
- ],
- [
- Buffer.from (domainStructHeader, 'hex'),
- Buffer.from (addressPadding, 'hex'),
- order['exchangeAddress']
- ]
- );
- const orderStructHash = ethAbi.soliditySHA3 (
- [
- 'bytes',
- 'bytes',
- 'address',
- 'bytes',
- 'address',
- 'bytes',
- 'address',
- 'bytes',
- 'address',
- 'uint256',
- 'uint256',
- 'uint256',
- 'uint256',
- 'uint256',
- 'uint256',
- 'string',
- 'string'
- ],
- [
- Buffer.from (orderSchemaHash, 'hex'),
- Buffer.from (addressPadding, 'hex'),
- order['makerAddress'],
- Buffer.from (addressPadding, 'hex'),
- order['takerAddress'],
- Buffer.from (addressPadding, 'hex'),
- order['feeRecipientAddress'],
- Buffer.from (addressPadding, 'hex'),
- order['senderAddress'],
- order['makerAssetAmount'],
- order['takerAssetAmount'],
- order['makerFee'],
- order['takerFee'],
- order['expirationTimeSeconds'],
- order['salt'],
- ethUtil.keccak (Buffer.from (order['makerAssetData'].slice (2), 'hex')),
- ethUtil.keccak (Buffer.from (order['takerAssetData'].slice (2), 'hex')),
- ]
- );
- return '0x' + ethUtil.keccak (Buffer.concat ([
- Buffer.from (header, 'hex'),
- domainStructHash,
- orderStructHash
- ])).toString ('hex');
- }
-
- signZeroExOrderV2 (order, privateKey) {
- const orderHash = this.getZeroExOrderHashV2 (order);
- const signature = this.signMessage (orderHash, privateKey);
- return this.extend (order, {
- 'orderHash': orderHash,
- 'signature': this.convertECSignatureToSignatureHex (signature),
- })
- }
-
- convertECSignatureToSignatureHex (signature) {
- // https://github.com/0xProject/0x-monorepo/blob/development/packages/order-utils/src/signature_utils.ts
- let v = signature.v;
- if (v !== 27 && v !== 28) {
- v = v + 27;
- }
- return '0x' + v.toString (16) + signature['r'].slice (-64) + signature['s'].slice (-64) + '03'
- }
-
- static remove0xPrefix (hexData) {
+ remove0xPrefix (hexData) {
if (hexData.slice (0, 2) === '0x') {
return hexData.slice (2)
} else {
@@ -1441,7 +1350,7 @@ module.exports = class Exchange {
hashMessage (message) {
// takes a hex encoded message
- const binaryMessage = this.base16ToBinary (Exchange.remove0xPrefix (message))
+ const binaryMessage = this.base16ToBinary (this.remove0xPrefix (message))
const prefix = this.stringToBinary ('\x19Ethereum Signed Message:\n' + binaryMessage.sigBytes)
return '0x' + this.hash (this.binaryConcat (prefix, binaryMessage), 'keccak', 'hex')
}
@@ -1459,6 +1368,13 @@ module.exports = class Exchange {
return this.signHash (this.hashMessage (message), privateKey.slice (-64))
}
+ signMessageString (message, privateKey) {
+ // still takes the input as a hex string
+ // same as above but returns a string instead of an object
+ const signature = this.signMessage (message, privateKey)
+ return signature['r'] + this.remove0xPrefix (signature['s']) + this.binaryToBase16 (this.numberToBE (signature['v']));
+ }
+
oath () {
if (typeof this.twofa !== 'undefined') {
return this.totp (this.twofa)
diff --git a/TaskServer/node_modules/ccxt/js/base/errorHierarchy.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/errorHierarchy.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/base/errorHierarchy.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/errorHierarchy.js
diff --git a/TaskServer/node_modules/ccxt/js/base/errors.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/errors.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/base/errors.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/errors.js
diff --git a/TaskServer/node_modules/ccxt/js/base/functions.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/base/functions.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions.js
diff --git a/TaskServer/node_modules/ccxt/js/base/functions/crypto.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/crypto.js
similarity index 90%
rename from TaskServer/node_modules/ccxt/js/base/functions/crypto.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/crypto.js
index 269bd37fb..3cdd9a932 100644
--- a/TaskServer/node_modules/ccxt/js/base/functions/crypto.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/crypto.js
@@ -4,10 +4,12 @@
const CryptoJS = require ('../../static_dependencies/crypto-js/crypto-js')
const { capitalize } = require ('./string')
-const { stringToBase64, utf16ToBase64, urlencodeBase64 } = require ('./encode')
+const { stringToBase64, urlencodeBase64 } = require ('./encode')
const NodeRSA = require ('./../../static_dependencies/node-rsa/NodeRSA')
-const { numberToLE } = require ('./encode')
-const EC = require ('./../../static_dependencies/elliptic/lib/elliptic').ec
+const { binaryToBase58, byteArrayToWordArray } = require ('./encode')
+const elliptic = require ('./../../static_dependencies/elliptic/lib/elliptic')
+const EC = elliptic.ec
+const EDDSA = elliptic.eddsa
const { ArgumentsRequired } = require ('./../errors')
const BN = require ('../../static_dependencies/BN/bn.js')
@@ -96,6 +98,14 @@ function ecdsa (request, secret, algorithm = 'p256', hashFunction = undefined, f
}
}
+
+function eddsa (request, secret, algorithm = 'ed25519') {
+ // used for waves.exchange (that's why the output is base58)
+ const curve = new EDDSA (algorithm)
+ const signature = curve.signModified (request, secret)
+ return binaryToBase58 (byteArrayToWordArray (signature.toBytes ()))
+}
+
/* ------------------------------------------------------------------------ */
const totp = (secret) => {
@@ -142,6 +152,7 @@ module.exports = {
totp,
rsa,
ecdsa,
+ eddsa,
}
/* ------------------------------------------------------------------------ */
diff --git a/TaskServer/node_modules/ccxt/js/base/functions/encode.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/encode.js
similarity index 57%
rename from TaskServer/node_modules/ccxt/js/base/functions/encode.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/encode.js
index 843fdb0ad..0b4331ccf 100644
--- a/TaskServer/node_modules/ccxt/js/base/functions/encode.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/encode.js
@@ -6,6 +6,14 @@ const CryptoJS = require ('../../static_dependencies/crypto-js/crypto-js')
const qs = require ('../../static_dependencies/qs/index')
const BN = require ('../../static_dependencies/BN/bn')
+
+/* ------------------------------------------------------------------------ */
+
+// global vars for base58 encoding
+const base58Alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
+let base58Decoder = null
+let base58Encoder = null
+
/* ------------------------------------------------------------------------ */
module.exports =
@@ -19,14 +27,8 @@ module.exports =
((object[0] === '{') || (object[0] === '['))
)
- , stringToBinary (str) {
- const arr = new Uint8Array (str.length)
- for (let i = 0; i < str.length; i++) { arr[i] = str.charCodeAt (i); }
- return CryptoJS.lib.WordArray.create (arr)
- }
-
+ , stringToBinary: string => CryptoJS.enc.Latin1.parse (string)
, stringToBase64: string => CryptoJS.enc.Latin1.parse (string).toString (CryptoJS.enc.Base64)
- , utf16ToBase64: string => CryptoJS.enc.Utf16 .parse (string).toString (CryptoJS.enc.Base64)
, base64ToBinary: string => CryptoJS.enc.Base64.parse (string)
, base64ToString: string => CryptoJS.enc.Base64.parse (string).toString (CryptoJS.enc.Utf8)
, binaryToBase64: binary => binary.toString (CryptoJS.enc.Base64)
@@ -56,9 +58,54 @@ module.exports =
const hexArray = new BN (n).toArray ('be', padding)
return byteArrayToWordArray (hexArray)
}
+
+ , base58ToBinary: (string) => {
+ if (!base58Decoder) {
+ base58Decoder = {}
+ base58Encoder = {}
+ for (let i = 0; i < 58; i++) {
+ const c = base58Alphabet[i]
+ const bigNum = new BN (i)
+ base58Decoder[c] = bigNum
+ base58Encoder[bigNum] = c
+ }
+ }
+ let result = new BN (0)
+ const base = new BN (58)
+ for (let i = 0; i < string.length; i++) {
+ const character = string[i]
+ result.imul (base)
+ result.iadd (base58Decoder[character])
+ }
+ return byteArrayToWordArray (result.toArray ('be'))
+ }
+
+ , binaryToBase58: (wordArray) => {
+ if (!base58Encoder) {
+ base58Decoder = {}
+ base58Encoder = {}
+ for (let i = 0; i < 58; i++) {
+ const c = base58Alphabet[i]
+ const bigNum = new BN (i)
+ base58Decoder[c] = bigNum
+ base58Encoder[bigNum] = c
+ }
+ }
+ const base = new BN (58)
+ // hex is only compatible encoding between cryptojs and BN
+ const hexString = wordArray.toString (CryptoJS.enc.Hex)
+ let result = new BN (hexString, 16)
+ let string = []
+ while (!result.isZero ()) {
+ const { div, mod } = result.divmod (base)
+ result = div
+ string.push (base58Encoder[mod])
+ }
+ return string.reverse ().join ('')
+ }
}
-function byteArrayToWordArray(ba) {
+function byteArrayToWordArray (ba) {
const wa = []
for (let i = 0; i < ba.length; i++) {
wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i)
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/generic.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/generic.js
new file mode 100644
index 000000000..be2e7e9ba
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/generic.js
@@ -0,0 +1,236 @@
+"use strict";
+
+// ----------------------------------------------------------------------------
+
+const { isObject, isNumber, isDictionary, isArray } = require ('./type')
+
+// ----------------------------------------------------------------------------
+
+const keys = Object.keys
+ , values = (x) => ((!isArray (x)) ? Object.values (x) : x) // don't copy arrays if they're already arrays
+ , index = (x) => new Set (values (x))
+ , extend = (...args) => Object.assign ({}, ...args) // NB: side-effect free
+ , clone = (x) => (isArray (x) ? Array.from (x) : extend (x)) // clone arrays or objects
+
+// ----------------------------------------------------------------------------
+
+module.exports = {
+ keys
+ , values
+ , extend
+ , clone
+ , index
+ , ordered: (x) => x // a stub to keep assoc keys in order (in JS it does nothing, it's mostly for Python)
+ , unique: (x) => Array.from (index (x))
+ , arrayConcat: (a, b) => a.concat (b)
+
+ // ------------------------------------------------------------------------
+
+ , inArray (needle, haystack) {
+
+ return haystack.includes (needle)
+ }
+
+ , toArray (object) {
+
+ return Object.values (object)
+ }
+
+ , isEmpty (object) {
+ if (!object) {
+ return true
+ }
+ return (Array.isArray (object) ? object : Object.keys (object)).length < 1;
+ }
+
+ // ------------------------------------------------------------------------
+
+ , keysort (x, out = {}) {
+
+ for (const k of keys (x).sort ())
+ out[k] = x[k]
+
+ return out
+ }
+
+ // ------------------------------------------------------------------------
+
+ /*
+ Accepts a map/array of objects and a key name to be used as an index:
+ array = [
+ { someKey: 'value1', anotherKey: 'anotherValue1' },
+ { someKey: 'value2', anotherKey: 'anotherValue2' },
+ { someKey: 'value3', anotherKey: 'anotherValue3' },
+ ]
+ key = 'someKey'
+
+ Returns a map:
+ {
+ value1: { someKey: 'value1', anotherKey: 'anotherValue1' },
+ value2: { someKey: 'value2', anotherKey: 'anotherValue2' },
+ value3: { someKey: 'value3', anotherKey: 'anotherValue3' },
+ }
+ */
+
+ , indexBy (x, k, out = {}) {
+
+ for (const v of values (x)) {
+ if (k in v) {
+ out[v[k]] = v
+ }
+ }
+
+ return out
+ }
+
+ // ------------------------------------------------------------------------
+
+ /*
+ Accepts a map/array of objects and a key name to be used as a grouping parameter:
+ array = [
+ { someKey: 'value1', anotherKey: 'anotherValue1' },
+ { someKey: 'value1', anotherKey: 'anotherValue2' },
+ { someKey: 'value3', anotherKey: 'anotherValue3' },
+ ]
+ key = 'someKey'
+
+ Returns a map:
+ {
+ value1: [
+ { someKey: 'value1', anotherKey: 'anotherValue1' },
+ { someKey: 'value1', anotherKey: 'anotherValue2' },
+ ]
+ value3: [
+ { someKey: 'value3', anotherKey: 'anotherValue3' }
+ ],
+ }
+ */
+
+ , groupBy (x, k, out = {}) {
+
+ for (const v of values (x)) {
+ if (k in v) {
+ const p = v[k]
+ out[p] = out[p] || []
+ out[p].push (v)
+ }
+ }
+ return out
+ }
+
+ // ------------------------------------------------------------------------
+
+ /*
+ Accepts a map/array of objects, a key name and a key value to be used as a filter:
+ array = [
+ { someKey: 'value1', anotherKey: 'anotherValue1' },
+ { someKey: 'value2', anotherKey: 'anotherValue2' },
+ { someKey: 'value3', anotherKey: 'anotherValue3' },
+ ]
+ key = 'someKey'
+ value = 'value1'
+
+ Returns an array:
+ [
+ value1: { someKey: 'value1', anotherKey: 'anotherValue1' },
+ ]
+ */
+
+ , filterBy (x, k, value = undefined, out = []) {
+
+ for (const v of values (x)) {
+ if (v[k] === value) {
+ out.push (v)
+ }
+ }
+
+ return out
+ }
+
+ // ------------------------------------------------------------------------
+ // NB: MUTATES ARRAY!
+
+ , sortBy: (array, key, descending = false, direction = descending ? -1 : 1) => array.sort ((a, b) => {
+ if (a[key] < b[key]) {
+ return -direction
+ } else if (a[key] > b[key]) {
+ return direction
+ } else {
+ return 0
+ }
+ })
+
+ // ------------------------------------------------------------------------
+
+ , flatten: function flatten (x, out = []) {
+
+ for (const v of x) {
+ if (isArray (v)) {
+ flatten (v, out)
+ } else {
+ out.push (v)
+ }
+ }
+
+ return out
+ }
+
+ // ------------------------------------------------------------------------
+
+ , pluck: (x, k) => values (x).filter ((v) => k in v).map ((v) => v[k])
+
+ // ------------------------------------------------------------------------
+
+ , omit (x, ...args) {
+
+ if (!Array.isArray (x)) {
+
+ const out = clone (x)
+
+ for (const k of args) {
+ if (isArray (k)) { // omit (x, ['a', 'b'])
+ for (const kk of k) {
+ delete out[kk]
+ }
+ } else {
+ delete out[k] // omit (x, 'a', 'b')
+ }
+ }
+
+ return out
+ }
+
+ return x
+ }
+
+ // ------------------------------------------------------------------------
+
+ , sum (...xs) {
+
+ const ns = xs.filter (isNumber) // leave only numbers
+
+ return (ns.length > 0) ? ns.reduce ((a, b) => a + b, 0) : undefined
+ }
+
+ // ------------------------------------------------------------------------
+
+ , deepExtend: function deepExtend (...xs) {
+ let out = undefined
+ for (const x of xs) {
+ if (isDictionary (x)) {
+ if (!isDictionary (out)) {
+ out = {}
+ }
+ for (const k in x) {
+ out[k] = deepExtend (out[k], x[k])
+ }
+ } else {
+ out = x
+ }
+ }
+ return out
+ }
+
+// ----------------------------------------------------------------------------
+
+}
diff --git a/TaskServer/node_modules/ccxt/js/base/functions/misc.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/misc.js
similarity index 90%
rename from TaskServer/node_modules/ccxt/js/base/functions/misc.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/misc.js
index 72570df00..7c12a1191 100644
--- a/TaskServer/node_modules/ccxt/js/base/functions/misc.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/misc.js
@@ -1,7 +1,7 @@
'use strict';
const { ROUND_UP, ROUND_DOWN } = require ('./number')
-const { NotSupported } = require ('./../errors')
+const { NotSupported } = require ('../errors')
//-------------------------------------------------------------------------
// converts timeframe to seconds
@@ -48,8 +48,9 @@ const buildOHLCVC = (trades, timeframe = '1m', since = -Infinity, limit = Infini
for (let i = 0; i <= oldest; i++) {
const trade = trades[i];
- if (trade.timestamp < since)
+ if (trade.timestamp < since) {
continue;
+ }
const openingTime = Math.floor (trade.timestamp / ms) * ms; // shift to the edge of m/h/d (but not M)
const candle = ohlcvs.length - 1;
@@ -100,6 +101,10 @@ const implodeParams = (string, params) => {
return string
}
+function vwap (baseVolume, quoteVolume) {
+ return ((baseVolume !== undefined) && (quoteVolume !== undefined) && (baseVolume > 0)) ? (quoteVolume / baseVolume) : undefined
+}
+
/* ------------------------------------------------------------------------ */
module.exports = {
@@ -115,7 +120,7 @@ module.exports = {
}
}
- return Object.keys (result).map (price => [parseFloat (price), parseFloat (result[price])])
+ return Object.keys (result).map ((price) => [parseFloat (price), parseFloat (result[price])])
},
parseTimeframe,
@@ -125,7 +130,9 @@ module.exports = {
ROUND_DOWN,
implodeParams,
- extractParams
+ extractParams,
+
+ vwap,
}
/* ------------------------------------------------------------------------ */
diff --git a/TaskServer/node_modules/ccxt/js/base/functions/number.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/number.js
similarity index 96%
rename from TaskServer/node_modules/ccxt/js/base/functions/number.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/number.js
index 82c8f0f28..cfd6e7db3 100644
--- a/TaskServer/node_modules/ccxt/js/base/functions/number.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/number.js
@@ -47,11 +47,12 @@ function numberToString (x) { // avoids scientific notation for too large and to
const s = x.toString ()
if (Math.abs (x) < 1.0) {
- const e = parseInt (s.split ('e-')[1])
+ const n_e = s.split ('e-')
+ const n = n_e[0].replace ('.', '')
+ const e = parseInt (n_e[1])
const neg = (s[0] === '-')
if (e) {
- x *= Math.pow (10, e - 1)
- x = (neg ? '-' : '') + '0.' + (new Array (e)).join ('0') + x.toString ().substring (neg ? 3 : 2)
+ x = (neg ? '-' : '') + '0.' + (new Array (e)).join ('0') + n.substring (neg)
return x
}
} else {
@@ -65,7 +66,7 @@ function numberToString (x) { // avoids scientific notation for too large and to
return m[0] + m[1] + (new Array (e + 1)).join ('0')
}
}
- return s;
+ return s
}
//-----------------------------------------------------------------------------
@@ -95,10 +96,13 @@ const decimalToPrecision = (x, roundingMode
, countingMode = DECIMAL_PLACES
, paddingMode = NO_PADDING) => {
- if (numPrecisionDigits < 0) {
- if (countingMode === TICK_SIZE) {
- throw new Error (`TICK_SIZE cant be used with negative numPrecisionDigits`)
+ if (countingMode === TICK_SIZE) {
+ if (numPrecisionDigits <= 0) {
+ throw new Error ('TICK_SIZE cant be used with negative or zero numPrecisionDigits')
}
+ }
+
+ if (numPrecisionDigits < 0) {
const toNearest = Math.pow (10, -numPrecisionDigits)
if (roundingMode === ROUND) {
return (toNearest * decimalToPrecision (x / toNearest, roundingMode, 0, countingMode, paddingMode)).toString ()
@@ -110,7 +114,7 @@ const decimalToPrecision = (x, roundingMode
/* handle tick size */
if (countingMode === TICK_SIZE) {
- const precisionDigitsString = decimalToPrecision (numPrecisionDigits, ROUND, 100, DECIMAL_PLACES, NO_PADDING)
+ const precisionDigitsString = decimalToPrecision (numPrecisionDigits, ROUND, 22, DECIMAL_PLACES, NO_PADDING)
const newNumPrecisionDigits = precisionFromString (precisionDigitsString)
let missing = x % numPrecisionDigits
// See: https://github.com/ccxt/ccxt/pull/6486
diff --git a/TaskServer/node_modules/ccxt/js/base/functions/platform.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/platform.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/base/functions/platform.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/platform.js
diff --git a/TaskServer/node_modules/ccxt/js/base/functions/string.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/string.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/base/functions/string.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/string.js
diff --git a/TaskServer/node_modules/ccxt/js/base/functions/throttle.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/throttle.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/base/functions/throttle.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/throttle.js
diff --git a/TaskServer/node_modules/ccxt/js/base/functions/time.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/time.js
similarity index 88%
rename from TaskServer/node_modules/ccxt/js/base/functions/time.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/time.js
index 83d646d17..a27c2ff25 100644
--- a/TaskServer/node_modules/ccxt/js/base/functions/time.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/time.js
@@ -6,6 +6,17 @@ const now = Date.now // TODO: figure out how to utilize performance.now () prope
const microseconds = () => now () * 1000 // TODO: utilize performance.now for that purpose
const milliseconds = now
const seconds = () => Math.floor (now () / 1000)
+const uuidv1 = () => {
+ const biasSeconds = 12219292800 // seconds from 15th Oct 1572 to Jan 1st 1970
+ const bias = biasSeconds * 10000000 // in hundreds of nanoseconds
+ const time = microseconds () * 10 + bias
+ const timeHex = time.toString (16)
+ const arranged = timeHex.slice (7, 15) + timeHex.slice (3, 7) + '1' + timeHex.slice (0, 3)
+ // these should be random, but we're not making more than 10 requests per microsecond so who cares
+ const clockId = '9696' // a 14 bit number
+ const macAddress = 'ff'.repeat (6)
+ return arranged + clockId + macAddress
+}
/* ------------------------------------------------------------------------ */
@@ -115,6 +126,10 @@ const parseDate = (x) => {
return parse8601 (x);
}
+const rfc2616 = (timestamp = undefined) => {
+ return new Date (timestamp).toUTCString ();
+}
+
const mdy = (timestamp, infix = '-') => {
infix = infix || ''
const date = new Date (timestamp)
@@ -162,6 +177,8 @@ module.exports =
, seconds
, iso8601
, parse8601
+ , rfc2616
+ , uuidv1
, parseDate
, mdy
, ymd
diff --git a/TaskServer/node_modules/ccxt/js/base/functions/type.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/type.js
similarity index 93%
rename from TaskServer/node_modules/ccxt/js/base/functions/type.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/type.js
index 6c2ed66bc..dec3acf7a 100644
--- a/TaskServer/node_modules/ccxt/js/base/functions/type.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/base/functions/type.js
@@ -6,9 +6,10 @@ const isNumber = Number.isFinite
, isInteger = Number.isInteger
, isArray = Array.isArray
, hasProps = o => ((o !== undefined) && (o !== null))
- , isString = s => (typeof s === 'string')
+ , isString = s => (typeof s === 'string')
, isObject = o => ((o !== null) && (typeof o === 'object'))
- , isDictionary = o => (isObject (o) && !isArray (o))
+ , isRegExp = o => (o instanceof RegExp)
+ , isDictionary = o => (isObject (o) && (Object.getPrototypeOf (o) === Object.prototype) && !isArray (o) && !isRegExp (o))
, isStringCoercible = x => ((hasProps (x) && x.toString) || isNumber (x))
/* ............................................. */
diff --git a/TaskServer/node_modules/ccxt/js/bcex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bcex.js
similarity index 99%
rename from TaskServer/node_modules/ccxt/js/bcex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bcex.js
index fbb7b4271..22eb628a3 100644
--- a/TaskServer/node_modules/ccxt/js/bcex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bcex.js
@@ -12,20 +12,22 @@ module.exports = class bcex extends Exchange {
return this.deepExtend (super.describe (), {
'id': 'bcex',
'name': 'BCEX',
- 'countries': [ 'CN', 'CA' ],
+ 'countries': [ 'CN', 'HK' ],
'version': '1',
'has': {
- 'fetchBalance': true,
- 'fetchMarkets': true,
- 'createOrder': true,
'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': 'emulated',
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrders': true,
+ 'fetchOrderBook': true,
'fetchTicker': true,
'fetchTickers': false,
'fetchTrades': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchClosedOrders': 'emulated',
- 'fetchOpenOrders': true,
'fetchTradingLimits': true,
},
'urls': {
@@ -96,6 +98,10 @@ module.exports = class bcex extends Exchange {
'参数非法': InvalidOrder, // {'code': 1, 'msg': '参数非法'} - 'Parameter illegal'
'订单信息不存在': OrderNotFound, // {'code': 1, 'msg': '订单信息不存在'} - 'Order information does not exist'
},
+ 'commonCurrencies': {
+ 'UNI': 'UNI COIN',
+ 'PNT': 'Penta',
+ },
'options': {
'limits': {
// hardcoding is deprecated, using these predefined values is not recommended, use loadTradingLimits instead
@@ -552,8 +558,10 @@ module.exports = class bcex extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
diff --git a/TaskServer/node_modules/ccxt/js/bequant.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bequant.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/bequant.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bequant.js
diff --git a/TaskServer/node_modules/ccxt/js/bibox.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bibox.js
similarity index 87%
rename from TaskServer/node_modules/ccxt/js/bibox.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bibox.js
index 083fccbe2..5f1e30c04 100644
--- a/TaskServer/node_modules/ccxt/js/bibox.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bibox.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, AccountSuspended, ArgumentsRequired, AuthenticationError, DDoSProtection, ExchangeNotAvailable, InvalidOrder, OrderNotFound, PermissionDenied, InsufficientFunds } = require ('./base/errors');
+const { ExchangeError, AccountSuspended, ArgumentsRequired, AuthenticationError, DDoSProtection, ExchangeNotAvailable, InvalidOrder, OrderNotFound, PermissionDenied, InsufficientFunds, BadSymbol } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -14,22 +14,29 @@ module.exports = class bibox extends Exchange {
'name': 'Bibox',
'countries': [ 'CN', 'US', 'KR' ],
'version': 'v1',
+ 'hostname': 'bibox365.com',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'publicAPI': false,
+ 'createMarketOrder': false, // or they will return https://github.com/ccxt/ccxt/issues/2338
+ 'createOrder': true,
'fetchBalance': true,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
+ 'fetchClosedOrders': true,
'fetchCurrencies': true,
+ 'fetchDeposits': true,
'fetchDepositAddress': true,
'fetchFundingFees': true,
- 'fetchTickers': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
- 'createMarketOrder': false, // or they will return https://github.com/ccxt/ccxt/issues/2338
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ 'publicAPI': false,
'withdraw': true,
},
'timeframes': {
@@ -47,13 +54,13 @@ module.exports = class bibox extends Exchange {
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/51840849/77257418-3262b000-6c85-11ea-8fb8-20bdf20b3592.jpg',
- 'api': 'https://api.bibox.com',
- 'www': 'https://www.bibox.com',
+ 'api': 'https://api.{hostname}',
+ 'www': 'https://www.bibox365.com',
'doc': [
'https://biboxcom.github.io/en/',
],
'fees': 'https://bibox.zendesk.com/hc/en-us/articles/360002336133',
- 'referral': 'https://w2.bibox.com/login/register?invite_code=05Kj3I',
+ 'referral': 'https://w2.bibox365.com/login/register?invite_code=05Kj3I',
},
'api': {
'public': {
@@ -105,12 +112,15 @@ module.exports = class bibox extends Exchange {
'2068': InvalidOrder, // The number of orders can not be less than
'2085': InvalidOrder, // Order quantity is too small
'3012': AuthenticationError, // invalid apiKey
+ '3016': BadSymbol, // Trading pair error
'3024': PermissionDenied, // wrong apikey permissions
'3025': AuthenticationError, // signature failed
'4000': ExchangeNotAvailable, // current network is unstable
'4003': DDoSProtection, // server busy please try again later
},
'commonCurrencies': {
+ 'BOX': 'DefiBox',
+ 'BPT': 'BlockPool Token',
'KEY': 'Bihu',
'MTC': 'MTC Mesh Network', // conflict with MTC Docademic doc.com Token https://github.com/ccxt/ccxt/issues/6081 https://github.com/ccxt/ccxt/issues/3025
'PAI': 'PCHAIN',
@@ -271,7 +281,8 @@ module.exports = class bibox extends Exchange {
};
const response = await this.publicGetMdata (this.extend (request, params));
const tickers = this.parseTickers (response['result'], symbols);
- return this.indexBy (tickers, 'symbol');
+ const result = this.indexBy (tickers, 'symbol');
+ return this.filterByArray (result, 'symbol', symbols);
}
parseTrade (trade, market = undefined) {
@@ -314,7 +325,7 @@ module.exports = class bibox extends Exchange {
}
if (feeCost !== undefined) {
fee = {
- 'cost': feeCost,
+ 'cost': -feeCost,
'currency': feeCurrency,
'rate': feeRate,
};
@@ -365,9 +376,19 @@ module.exports = class bibox extends Exchange {
return this.parseOrderBook (response['result'], this.safeFloat (response['result'], 'update_time'), 'bids', 'asks', 'price', 'volume');
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "time":1591448220000,
+ // "open":"0.02507029",
+ // "high":"0.02507029",
+ // "low":"0.02506349",
+ // "close":"0.02506349",
+ // "vol":"5.92000000"
+ // }
+ //
return [
- ohlcv['time'],
+ this.safeInteger (ohlcv, 'time'),
this.safeFloat (ohlcv, 'open'),
this.safeFloat (ohlcv, 'high'),
this.safeFloat (ohlcv, 'low'),
@@ -386,7 +407,19 @@ module.exports = class bibox extends Exchange {
'size': limit,
};
const response = await this.publicGetMdata (this.extend (request, params));
- return this.parseOHLCVs (response['result'], market, timeframe, since, limit);
+ //
+ // {
+ // "result":[
+ // {"time":1591448220000,"open":"0.02507029","high":"0.02507029","low":"0.02506349","close":"0.02506349","vol":"5.92000000"},
+ // {"time":1591448280000,"open":"0.02506449","high":"0.02506975","low":"0.02506108","close":"0.02506843","vol":"5.72000000"},
+ // {"time":1591448340000,"open":"0.02506698","high":"0.02506698","low":"0.02506452","close":"0.02506519","vol":"4.86000000"},
+ // ],
+ // "cmd":"kline",
+ // "ver":"1.1"
+ // }
+ //
+ const result = this.safeValue (response, 'result', []);
+ return this.parseOHLCVs (result, market, timeframe, since, limit);
}
async fetchCurrencies (params = {}) {
@@ -398,6 +431,52 @@ module.exports = class bibox extends Exchange {
'body': {},
};
const response = await this.privatePostTransfer (this.extend (request, params));
+ //
+ // {
+ // "result":[
+ // {
+ // "result":[
+ // {
+ // "totalBalance":"14.57582269",
+ // "balance":"14.57582269",
+ // "freeze":"0.00000000",
+ // "id":60,
+ // "symbol":"USDT",
+ // "icon_url":"/appimg/USDT_icon.png",
+ // "describe_url":"[{\"lang\":\"zh-cn\",\"link\":\"https://bibox.zendesk.com/hc/zh-cn/articles/115004798234\"},{\"lang\":\"en-ww\",\"link\":\"https://bibox.zendesk.com/hc/en-us/articles/115004798234\"}]",
+ // "name":"USDT",
+ // "enable_withdraw":1,
+ // "enable_deposit":1,
+ // "enable_transfer":1,
+ // "confirm_count":2,
+ // "is_erc20":1,
+ // "forbid_info":null,
+ // "describe_summary":"[{\"lang\":\"zh-cn\",\"text\":\"USDT 是 Tether 公司推出的基于稳定价值货币美元(USD)的代币 Tether USD(简称USDT),1USDT=1美元,用户可以随时使用 USDT 与 USD 进行1:1的兑换。\"},{\"lang\":\"en-ww\",\"text\":\"USDT is a cryptocurrency asset issued on the Bitcoin blockchain via the Omni Layer Protocol. Each USDT unit is backed by a U.S Dollar held in the reserves of the Tether Limited and can be redeemed through the Tether Platform.\"}]",
+ // "total_amount":4776930644,
+ // "supply_amount":4642367414,
+ // "price":"--",
+ // "contract_father":"OMNI",
+ // "supply_time":"--",
+ // "comment":null,
+ // "contract":"31",
+ // "original_decimals":8,
+ // "deposit_type":0,
+ // "hasCobo":0,
+ // "BTCValue":"0.00126358",
+ // "CNYValue":"100.93381445",
+ // "USDValue":"14.57524654",
+ // "children":[
+ // {"type":"OMNI","symbol":"USDT","enable_deposit":1,"enable_withdraw":1,"confirm_count":2},
+ // {"type":"TRC20","symbol":"tUSDT","enable_deposit":1,"enable_withdraw":1,"confirm_count":20},
+ // {"type":"ERC20","symbol":"eUSDT","enable_deposit":1,"enable_withdraw":1,"confirm_count":25}
+ // ]
+ // },
+ // ],
+ // "cmd":"transfer/coinList"
+ // }
+ // ]
+ // }
+ //
const currencies = this.safeValue (response, 'result');
const result = {};
for (let i = 0; i < currencies.length; i++) {
@@ -719,8 +798,10 @@ module.exports = class bibox extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': average,
@@ -907,7 +988,7 @@ module.exports = class bibox extends Exchange {
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- let url = this.urls['api'] + '/' + this.version + '/' + path;
+ let url = this.implodeParams (this.urls['api'], { 'hostname': this.hostname }) + '/' + this.version + '/' + path;
const cmds = this.json ([ params ]);
if (api === 'public') {
if (method !== 'GET') {
diff --git a/TaskServer/node_modules/ccxt/js/bigone.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bigone.js
similarity index 91%
rename from TaskServer/node_modules/ccxt/js/bigone.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bigone.js
index 31eb326e7..b589aceeb 100644
--- a/TaskServer/node_modules/ccxt/js/bigone.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bigone.js
@@ -17,16 +17,23 @@ module.exports = class bigone extends Exchange {
'rateLimit': 1200, // 500 request per 10 minutes
'has': {
'cancelAllOrders': true,
- 'createMarketOrder': false,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrders': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchWithdrawals': true,
'withdraw': true,
},
@@ -137,6 +144,7 @@ module.exports = class bigone extends Exchange {
},
},
'commonCurrencies': {
+ 'MBN': 'Mobilian Coin',
'ONE': 'BigONE Token',
},
});
@@ -247,24 +255,9 @@ module.exports = class bigone extends Exchange {
// "daily_change":"-0.000182"
// }
//
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (ticker, 'asset_pair_name');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
- const timestamp = this.milliseconds ();
+ const marketId = this.safeString (ticker, 'asset_pair_name');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const timestamp = undefined;
const close = this.safeFloat (ticker, 'close');
const bid = this.safeValue (ticker, 'bid', {});
const ask = this.safeValue (ticker, 'ask', {});
@@ -363,7 +356,21 @@ module.exports = class bigone extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetPing (params);
+ //
+ // {
+ // "data": {
+ // "timestamp": 1527665262168391000
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const timestamp = this.safeInteger (data, 'timestamp');
+ return parseInt (timestamp / 1000000);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -440,20 +447,7 @@ module.exports = class bigone extends Exchange {
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'amount');
const marketId = this.safeString (trade, 'asset_pair_name');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
let cost = undefined;
if (amount !== undefined) {
if (price !== undefined) {
@@ -584,7 +578,7 @@ module.exports = class bigone extends Exchange {
return this.parseTrades (trades, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// close: '0.021562',
@@ -645,8 +639,8 @@ module.exports = class bigone extends Exchange {
// ]
// }
//
- const ohlcvs = this.safeValue (response, 'data', []);
- return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async fetchBalance (params = {}) {
@@ -692,23 +686,8 @@ module.exports = class bigone extends Exchange {
// }
//
const id = this.safeString (order, 'id');
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'asset_pair_name');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'asset_pair_name');
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const price = this.safeFloat (order, 'price');
const amount = this.safeFloat (order, 'amount');
@@ -741,8 +720,10 @@ module.exports = class bigone extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': undefined,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': average,
@@ -758,12 +739,34 @@ module.exports = class bigone extends Exchange {
await this.loadMarkets ();
const market = this.market (symbol);
side = (side === 'buy') ? 'BID' : 'ASK';
+ const uppercaseType = type.toUpperCase ();
const request = {
'asset_pair_name': market['id'], // asset pair name BTC-USDT, required
'side': side, // order side one of "ASK"/"BID", required
'amount': this.amountToPrecision (symbol, amount), // order amount, string, required
- 'price': this.priceToPrecision (symbol, price), // order price, string, required
+ // 'price': this.priceToPrecision (symbol, price), // order price, string, required
+ 'type': uppercaseType,
+ // 'operator': 'GTE', // stop orders only, GTE greater than and equal, LTE less than and equal
+ // 'immediate_or_cancel': false, // limit orders only, must be false when post_only is true
+ // 'post_only': false, // limit orders only, must be false when immediate_or_cancel is true
};
+ if (uppercaseType === 'LIMIT') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ } else {
+ const isStopLimit = (uppercaseType === 'STOP_LIMIT');
+ const isStopMarket = (uppercaseType === 'STOP_MARKET');
+ if (isStopLimit || isStopMarket) {
+ const stopPrice = this.safeFloat2 (params, 'stop_price', 'stopPrice');
+ if (stopPrice === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder requires a stop_price parameter');
+ }
+ request['stop_price'] = this.priceToPrecision (symbol, stopPrice);
+ params = this.omit (params, [ 'stop_price', 'stopPrice' ]);
+ }
+ if (isStopLimit) {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ }
const response = await this.privatePostOrders (this.extend (request, params));
//
// {
@@ -1071,6 +1074,24 @@ module.exports = class bigone extends Exchange {
// "txid": "0x4643bb6b393ac20a6175c713175734a72517c63d6f73a3ca90a15356f2e967da0",
// }
//
+ // withdraw
+ //
+ // {
+ // "id":1077391,
+ // "customer_id":1082679,
+ // "amount":"21.9000000000000000",
+ // "txid":"",
+ // "is_internal":false,
+ // "kind":"on_chain",
+ // "state":"PENDING",
+ // "inserted_at":"2020-06-03T00:50:57+00:00",
+ // "updated_at":"2020-06-03T00:50:57+00:00",
+ // "memo":"",
+ // "target_address":"rDYtYT3dBeuw376rvHqoZBKW3UmvguoBAf",
+ // "fee":"0.1000000000000000",
+ // "asset_symbol":"XRP"
+ // }
+ //
const currencyId = this.safeString (transaction, 'asset_symbol');
const code = this.safeCurrencyCode (currencyId);
const id = this.safeInteger (transaction, 'id');
@@ -1204,35 +1225,25 @@ module.exports = class bigone extends Exchange {
// {
// "code":0,
// "message":"",
- // "data":[
- // {
- // "id":1,
- // "customer_id":7,
- // "asset_uuid":"50293b12-5be8-4f5b-b31d-d43cdd5ccc29",
- // "amount":"100",
- // "recipient":null,
- // "state":"PENDING",
- // "is_internal":true,
- // "note":"asdsadsad",
- // "kind":"on_chain",
- // "txid":"asdasdasdsadsadsad",
- // "confirms":5,
- // "inserted_at":null,
- // "updated_at":null,
- // "completed_at":null,
- // "commision":null,
- // "explain":""
- // }
- // ]
+ // "data":{
+ // "id":1077391,
+ // "customer_id":1082679,
+ // "amount":"21.9000000000000000",
+ // "txid":"",
+ // "is_internal":false,
+ // "kind":"on_chain",
+ // "state":"PENDING",
+ // "inserted_at":"2020-06-03T00:50:57+00:00",
+ // "updated_at":"2020-06-03T00:50:57+00:00",
+ // "memo":"",
+ // "target_address":"rDYtYT3dBeuw376rvHqoZBKW3UmvguoBAf",
+ // "fee":"0.1000000000000000",
+ // "asset_symbol":"XRP"
+ // }
// }
//
- const data = this.safeValue (response, 'data', []);
- const dataLength = data.length;
- if (dataLength < 1) {
- throw new ExchangeError (this.id + ' withdraw() returned an empty response');
- }
- const transaction = data[0];
- return this.parseTransaction (transaction, currency);
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTransaction (data, currency);
}
handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
diff --git a/TaskServer/node_modules/ccxt/js/binance.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/binance.js
similarity index 67%
rename from TaskServer/node_modules/ccxt/js/binance.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/binance.js
index 9c4cddc24..c9e459dfb 100644
--- a/TaskServer/node_modules/ccxt/js/binance.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/binance.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied, NotSupported } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, InvalidAddress, RateLimitExceeded, PermissionDenied, NotSupported, BadRequest, BadSymbol, AccountSuspended, OrderImmediatelyFillable } = require ('./base/errors');
const { ROUND, TRUNCATE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -19,25 +19,33 @@ module.exports = class binance extends Exchange {
'pro': true,
// new metainfo interface
'has': {
- 'fetchDepositAddress': true,
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchBidsAsks': true,
- 'fetchTickers': true,
- 'fetchTime': true,
- 'fetchOHLCV': true,
+ 'fetchClosedOrders': 'emulated',
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchFundingFees': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
'fetchOrder': true,
'fetchOrders': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': 'emulated',
- 'withdraw': true,
- 'fetchFundingFees': true,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
- 'fetchTransactions': false,
+ 'fetchOrderBook': true,
+ 'fetchStatus': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
- 'cancelAllOrders': true,
+ 'fetchTransactions': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1m',
@@ -59,15 +67,26 @@ module.exports = class binance extends Exchange {
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/29604020-d5483cdc-87ee-11e7-94c7-d1a8d9169293.jpg',
'test': {
+ 'dapiPublic': 'https://testnet.binancefuture.com/dapi/v1',
+ 'dapiPrivate': 'https://testnet.binancefuture.com/dapi/v1',
'fapiPublic': 'https://testnet.binancefuture.com/fapi/v1',
'fapiPrivate': 'https://testnet.binancefuture.com/fapi/v1',
+ 'fapiPrivateV2': 'https://testnet.binancefuture.com/fapi/v2',
+ 'public': 'https://testnet.binance.vision/api/v3',
+ 'private': 'https://testnet.binance.vision/api/v3',
+ 'v3': 'https://testnet.binance.vision/api/v3',
+ 'v1': 'https://testnet.binance.vision/api/v1',
},
'api': {
- 'web': 'https://www.binance.com',
'wapi': 'https://api.binance.com/wapi/v3',
'sapi': 'https://api.binance.com/sapi/v1',
+ 'dapiPublic': 'https://dapi.binance.com/dapi/v1',
+ 'dapiPrivate': 'https://dapi.binance.com/dapi/v1',
+ 'dapiData': 'https://dapi.binance.com/futures/data',
'fapiPublic': 'https://fapi.binance.com/fapi/v1',
'fapiPrivate': 'https://fapi.binance.com/fapi/v1',
+ 'fapiData': 'https://fapi.binance.com/futures/data',
+ 'fapiPrivateV2': 'https://fapi.binance.com/fapi/v2',
'public': 'https://api.binance.com/api/v3',
'private': 'https://api.binance.com/api/v3',
'v3': 'https://api.binance.com/api/v3',
@@ -82,12 +101,6 @@ module.exports = class binance extends Exchange {
'fees': 'https://www.binance.com/en/fee/schedule',
},
'api': {
- 'web': {
- 'get': [
- 'exchange/public/product',
- 'assetWithdraw/getAllAsset.html',
- ],
- },
// the API structure below will need 3-layer apidefs
'sapi': {
'get': [
@@ -112,7 +125,19 @@ module.exports = class binance extends Exchange {
'margin/myTrades',
'margin/maxBorrowable',
'margin/maxTransferable',
+ 'margin/isolated/transfer',
+ 'margin/isolated/account',
+ 'margin/isolated/pair',
+ 'margin/isolated/allPairs',
'futures/transfer',
+ 'futures/loan/borrow/history',
+ 'futures/loan/repay/history',
+ 'futures/loan/wallet',
+ 'futures/loan/configs',
+ 'futures/loan/calcAdjustLevel',
+ 'futures/loan/calcMaxAdjustAmount',
+ 'futures/loan/adjustCollateral/history',
+ 'futures/loan/liquidationHistory',
// https://binance-docs.github.io/apidocs/spot/en/#withdraw-sapi
'capital/config/getall', // get networks for withdrawing USDT ERC20 vs USDT Omni
'capital/deposit/address',
@@ -123,9 +148,12 @@ module.exports = class binance extends Exchange {
'sub-account/futures/account',
'sub-account/futures/accountSummary',
'sub-account/futures/positionRisk',
+ 'sub-account/futures/internalTransfer',
'sub-account/margin/account',
'sub-account/margin/accountSummary',
+ 'sub-account/spotSummary',
'sub-account/status',
+ 'sub-account/transfer/subUserHistory',
// lending endpoints
'lending/daily/product/list',
'lending/daily/userLeftQuota',
@@ -137,6 +165,20 @@ module.exports = class binance extends Exchange {
'lending/union/interestHistory',
'lending/project/list',
'lending/project/position/list',
+ // mining endpoints
+ 'mining/pub/algoList',
+ 'mining/pub/coinList',
+ 'mining/worker/detail',
+ 'mining/worker/list',
+ 'mining/payment/list',
+ 'mining/statistics/user/status',
+ 'mining/statistics/user/list',
+ // liquid swap endpoints
+ 'bswap/pools',
+ 'bswap/liquidity',
+ 'bswap/liquidityOps',
+ 'bswap/quote',
+ 'bswap/swap',
],
'post': [
'asset/dust',
@@ -147,22 +189,39 @@ module.exports = class binance extends Exchange {
'margin/loan',
'margin/repay',
'margin/order',
+ 'margin/isolated/create',
+ 'margin/isolated/transfer',
+ 'sub-account/margin/transfer',
'sub-account/margin/enable',
'sub-account/margin/enable',
'sub-account/futures/enable',
+ 'sub-account/futures/transfer',
+ 'sub-account/futures/internalTransfer',
+ 'sub-account/transfer/subToSub',
+ 'sub-account/transfer/subToMaster',
'userDataStream',
+ 'userDataStream/isolated',
'futures/transfer',
+ 'futures/loan/borrow',
+ 'futures/loan/repay',
+ 'futures/loan/adjustCollateral',
// lending
'lending/customizedFixed/purchase',
'lending/daily/purchase',
'lending/daily/redeem',
+ // liquid swap endpoints
+ 'bswap/liquidityAdd',
+ 'bswap/liquidityRemove',
+ 'bswap/swap',
],
'put': [
'userDataStream',
+ 'userDataStream/isolated',
],
'delete': [
'margin/order',
'userDataStream',
+ 'userDataStream/isolated',
],
},
'wapi': {
@@ -185,6 +244,75 @@ module.exports = class binance extends Exchange {
'sub-account/assets',
],
},
+ 'dapiPublic': {
+ 'get': [
+ 'ping',
+ 'time',
+ 'exchangeInfo',
+ 'depth',
+ 'trades',
+ 'historicalTrades',
+ 'aggTrades',
+ 'premiumIndex',
+ 'fundingRate',
+ 'klines',
+ 'continuousKlines',
+ 'indexPriceKlines',
+ 'markPriceKlines',
+ 'ticker/24hr',
+ 'ticker/price',
+ 'ticker/bookTicker',
+ 'allForceOrders',
+ 'openInterest',
+ ],
+ },
+ 'dapiData': {
+ 'get': [
+ 'openInterestHist',
+ 'topLongShortAccountRatio',
+ 'topLongShortPositionRatio',
+ 'globalLongShortAccountRatio',
+ 'takerBuySellVol',
+ 'basis',
+ ],
+ },
+ 'dapiPrivate': {
+ 'get': [
+ 'positionSide/dual',
+ 'order',
+ 'openOrder',
+ 'openOrders',
+ 'allOrders',
+ 'balance',
+ 'account',
+ 'positionMargin/history',
+ 'positionRisk',
+ 'userTrades',
+ 'income',
+ 'leverageBracket',
+ 'forceOrders',
+ 'adlQuantile',
+ ],
+ 'post': [
+ 'positionSide/dual',
+ 'order',
+ 'batchOrders',
+ 'countdownCancelAll',
+ 'leverage',
+ 'marginType',
+ 'positionMargin',
+ 'listenKey',
+ ],
+ 'put': [
+ 'listenKey',
+ ],
+ 'delete': [
+ 'order',
+ 'allOpenOrders',
+ 'batchOrders',
+ 'listenKey',
+ ],
+ },
'fapiPublic': {
'get': [
'ping',
@@ -202,19 +330,31 @@ module.exports = class binance extends Exchange {
'ticker/bookTicker',
'allForceOrders',
'openInterest',
- 'leverageBracket',
+ 'indexInfo',
+ ],
+ },
+ 'fapiData': {
+ 'get': [
+ 'openInterestHist',
+ 'topLongShortAccountRatio',
+ 'topLongShortPositionRatio',
+ 'globalLongShortAccountRatio',
+ 'takerlongshortRatio',
],
},
'fapiPrivate': {
'get': [
+ 'allForceOrders',
'allOrders',
'openOrder',
'openOrders',
'order',
'account',
'balance',
+ 'leverageBracket',
'positionMargin/history',
'positionRisk',
+ 'positionSide/dual',
'userTrades',
'income',
],
@@ -226,6 +366,7 @@ module.exports = class binance extends Exchange {
'order',
'leverage',
'listenKey',
+ 'countdownCancelAll',
],
'put': [
'listenKey',
@@ -237,6 +378,13 @@ module.exports = class binance extends Exchange {
'listenKey',
],
},
+ 'fapiPrivateV2': {
+ 'get': [
+ 'account',
+ 'balance',
+ 'positionRisk',
+ ],
+ },
'v3': {
'get': [
'ticker/price',
@@ -298,10 +446,9 @@ module.exports = class binance extends Exchange {
},
// exchange-specific options
'options': {
- 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades
- 'fetchTickersMethod': 'publicGetTicker24hr',
+ // 'fetchTradesMethod': 'publicGetAggTrades', // publicGetTrades, publicGetHistoricalTrades
'defaultTimeInForce': 'GTC', // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel
- 'defaultType': 'spot', // 'spot', 'future'
+ 'defaultType': 'spot', // 'spot', 'future', 'margin', 'delivery'
'hasAlreadyAuthenticatedSuccessfully': false,
'warnOnFetchOpenOrdersWithoutSymbol': true,
'recvWindow': 5 * 1000, // 5 sec, binance default
@@ -312,70 +459,81 @@ module.exports = class binance extends Exchange {
'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'
},
+ 'quoteOrderQty': true, // whether market orders support amounts in quote currency
},
+ // https://binance-docs.github.io/apidocs/spot/en/#error-codes-2
'exceptions': {
'API key does not exist': AuthenticationError,
- 'Order would trigger immediately.': InvalidOrder,
+ 'Order would trigger immediately.': OrderImmediatelyFillable,
+ 'Order would immediately match and take.': OrderImmediatelyFillable, // {"code":-2010,"msg":"Order would immediately match and take."}
'Account has insufficient balance for requested action.': InsufficientFunds,
'Rest API trading is not enabled.': ExchangeNotAvailable,
"You don't have permission.": PermissionDenied, // {"msg":"You don't have permission.","success":false}
'Market is closed.': ExchangeNotAvailable, // {"code":-1013,"msg":"Market is closed."}
+ 'Too many requests.': DDoSProtection, // {"msg":"Too many requests. Please try again later.","success":false}
'-1000': ExchangeNotAvailable, // {"code":-1000,"msg":"An unknown error occured while processing the request."}
+ '-1001': ExchangeNotAvailable, // 'Internal error; unable to process your request. Please try again.'
+ '-1002': AuthenticationError, // 'You are not authorized to execute this request.'
'-1003': RateLimitExceeded, // {"code":-1003,"msg":"Too much request weight used, current limit is 1200 request weight per 1 MINUTE. Please use the websocket for live updates to avoid polling the API."}
'-1013': InvalidOrder, // createOrder -> 'invalid quantity'/'invalid price'/MIN_NOTIONAL
+ '-1015': RateLimitExceeded, // 'Too many new orders; current limit is %s orders per %s.'
+ '-1016': ExchangeNotAvailable, // 'This service is no longer available.',
+ '-1020': BadRequest, // 'This operation is not supported.'
'-1021': InvalidNonce, // 'your time is ahead of server'
'-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."}
- '-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
- '-1128': ExchangeError, // {"code":-1128,"msg":"Combination of optional parameters invalid."}
+ '-1100': BadRequest, // createOrder(symbol, 1, asdf) -> 'Illegal characters found in parameter 'price'
+ '-1101': BadRequest, // Too many parameters; expected %s and received %s.
+ '-1102': BadRequest, // Param %s or %s must be sent, but both were empty
+ '-1103': BadRequest, // An unknown parameter was sent.
+ '-1104': BadRequest, // Not all sent parameters were read, read 8 parameters but was sent 9
+ '-1105': BadRequest, // Parameter %s was empty.
+ '-1106': BadRequest, // Parameter %s sent when not required.
+ '-1111': BadRequest, // Precision is over the maximum defined for this asset.
+ '-1112': InvalidOrder, // No orders on book for symbol.
+ '-1114': BadRequest, // TimeInForce parameter sent when not required.
+ '-1115': BadRequest, // Invalid timeInForce.
+ '-1116': BadRequest, // Invalid orderType.
+ '-1117': BadRequest, // Invalid side.
+ '-1118': BadRequest, // New client order ID was empty.
+ '-1119': BadRequest, // Original client order ID was empty.
+ '-1120': BadRequest, // Invalid interval.
+ '-1121': BadSymbol, // Invalid symbol.
+ '-1125': AuthenticationError, // This listenKey does not exist.
+ '-1127': BadRequest, // More than %s hours between startTime and endTime.
+ '-1128': BadRequest, // {"code":-1128,"msg":"Combination of optional parameters invalid."}
+ '-1130': BadRequest, // Data sent for paramter %s is not valid.
+ '-1131': BadRequest, // recvWindow must be less than 60000
'-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."
+ '-3005': InsufficientFunds, // {"code":-3005,"msg":"Transferring out not allowed. Transfer out amount exceeds max amount."}
+ '-3008': InsufficientFunds, // {"code":-3008,"msg":"Borrow not allowed. Your borrow amount has exceed maximum borrow amount."}
+ '-3010': ExchangeError, // {"code":-3010,"msg":"Repay not allowed. Repay amount exceeds borrow amount."}
+ '-3022': AccountSuspended, // You account's trading is banned.
},
});
}
- setSandboxMode (enabled) {
- if (enabled) { // eslint-disable-line no-extra-boolean-cast
- if ('test' in this.urls) {
- const type = this.safeString (this.options, 'defaultType', 'spot');
- if (type !== 'future') {
- throw new NotSupported (this.id + ' does not have a sandbox URL for ' + type + " markets, set exchange.options['defaultType'] = 'future' or don't use the sandbox for " + this.id);
- }
- if (typeof this.urls['api'] === 'string') {
- this.urls['api_backup'] = this.urls['api'];
- this.urls['api'] = this.urls['test'];
- } else {
- this.urls['api_backup'] = this.extend ({}, this.urls['api']);
- this.urls['api'] = this.extend ({}, this.urls['test']);
- }
- } else {
- throw new NotSupported (this.id + ' does not have a sandbox URL');
- }
- } else if ('api_backup' in this.urls) {
- if (typeof this.urls['api'] === 'string') {
- this.urls['api'] = this.urls['api_backup'];
- } else {
- this.urls['api'] = this.extend ({}, this.urls['api_backup']);
- }
- }
- }
-
nonce () {
return this.milliseconds () - this.options['timeDifference'];
}
async fetchTime (params = {}) {
const type = this.safeString2 (this.options, 'fetchTime', 'defaultType', 'spot');
- const method = (type === 'spot') ? 'publicGetTime' : 'fapiPublicGetTime';
+ let method = 'publicGetTime';
+ if (type === 'future') {
+ method = 'fapiPublicGetTime';
+ } else if (type === 'delivery') {
+ method = 'dapiPublicGetTime';
+ }
const response = await this[method] (params);
return this.safeInteger (response, 'serverTime');
}
- async loadTimeDifference () {
- const serverTime = await this.fetchTime ();
+ async loadTimeDifference (params = {}) {
+ const serverTime = await this.fetchTime (params);
const after = this.milliseconds ();
this.options['timeDifference'] = after - serverTime;
return this.options['timeDifference'];
@@ -385,10 +543,18 @@ module.exports = class binance extends Exchange {
const defaultType = this.safeString2 (this.options, 'fetchMarkets', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
- const method = (type === 'spot') ? 'publicGetExchangeInfo' : 'fapiPublicGetExchangeInfo';
+ if ((type !== 'spot') && (type !== 'future') && (type !== 'margin') && (type !== 'delivery')) {
+ throw new ExchangeError (this.id + " does not support '" + type + "' type, set exchange.options['defaultType'] to 'spot', 'margin', 'delivery' or 'future'"); // eslint-disable-line quotes
+ }
+ let method = 'publicGetExchangeInfo';
+ if (type === 'future') {
+ method = 'fapiPublicGetExchangeInfo';
+ } else if (type === 'delivery') {
+ method = 'dapiPublicGetExchangeInfo';
+ }
const response = await this[method] (query);
//
- // spot
+ // spot / margin
//
// {
// "timezone":"UTC",
@@ -428,7 +594,7 @@ module.exports = class binance extends Exchange {
// ],
// }
//
- // futures (fapi)
+ // futures/usdt-margined (fapi)
//
// {
// "timezone":"UTC",
@@ -463,6 +629,76 @@ module.exports = class binance extends Exchange {
// ]
// }
//
+ // delivery/coin-margined (dapi)
+ //
+ // {
+ // "timezone": "UTC",
+ // "serverTime": 1597667052958,
+ // "rateLimits": [
+ // {"rateLimitType":"REQUEST_WEIGHT","interval":"MINUTE","intervalNum":1,"limit":6000},
+ // {"rateLimitType":"ORDERS","interval":"MINUTE","intervalNum":1,"limit":6000}
+ // ],
+ // "exchangeFilters": [],
+ // "symbols": [
+ // {
+ // "symbol": "BTCUSD_200925",
+ // "pair": "BTCUSD",
+ // "contractType": "CURRENT_QUARTER",
+ // "deliveryDate": 1601020800000,
+ // "onboardDate": 1590739200000,
+ // "contractStatus": "TRADING",
+ // "contractSize": 100,
+ // "marginAsset": "BTC",
+ // "maintMarginPercent": "2.5000",
+ // "requiredMarginPercent": "5.0000",
+ // "baseAsset": "BTC",
+ // "quoteAsset": "USD",
+ // "pricePrecision": 1,
+ // "quantityPrecision": 0,
+ // "baseAssetPrecision": 8,
+ // "quotePrecision": 8,
+ // "equalQtyPrecision": 4,
+ // "filters": [
+ // {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"},
+ // {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"},
+ // {"stepSize":"0","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"},
+ // {"limit":200,"filterType":"MAX_NUM_ORDERS"},
+ // {"multiplierDown":"0.9500","multiplierUp":"1.0500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"}
+ // ],
+ // "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"],
+ // "timeInForce": ["GTC","IOC","FOK","GTX"]
+ // },
+ // {
+ // "symbol": "BTCUSD_PERP",
+ // "pair": "BTCUSD",
+ // "contractType": "PERPETUAL",
+ // "deliveryDate": 4133404800000,
+ // "onboardDate": 1596006000000,
+ // "contractStatus": "TRADING",
+ // "contractSize": 100,
+ // "marginAsset": "BTC",
+ // "maintMarginPercent": "2.5000",
+ // "requiredMarginPercent": "5.0000",
+ // "baseAsset": "BTC",
+ // "quoteAsset": "USD",
+ // "pricePrecision": 1,
+ // "quantityPrecision": 0,
+ // "baseAssetPrecision": 8,
+ // "quotePrecision": 8,
+ // "equalQtyPrecision": 4,
+ // "filters": [
+ // {"minPrice":"0.1","maxPrice":"100000","filterType":"PRICE_FILTER","tickSize":"0.1"},
+ // {"stepSize":"1","filterType":"LOT_SIZE","maxQty":"100000","minQty":"1"},
+ // {"stepSize":"1","filterType":"MARKET_LOT_SIZE","maxQty":"100000","minQty":"1"},
+ // {"limit":200,"filterType":"MAX_NUM_ORDERS"},
+ // {"multiplierDown":"0.8500","multiplierUp":"1.1500","multiplierDecimal":"4","filterType":"PERCENT_PRICE"}
+ // ],
+ // "orderTypes": ["LIMIT","MARKET","STOP","STOP_MARKET","TAKE_PROFIT","TAKE_PROFIT_MARKET","TRAILING_STOP_MARKET"],
+ // "timeInForce": ["GTC","IOC","FOK","GTX"]
+ // }
+ // ]
+ // }
+ //
if (this.options['adjustForTimeDifference']) {
await this.loadTimeDifference ();
}
@@ -470,25 +706,30 @@ module.exports = class binance extends Exchange {
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
- const future = ('maintMarginPercent' in market);
- const spot = !future;
- const marketType = spot ? 'spot' : 'future';
+ const spot = (type === 'spot');
+ const future = (type === 'future');
+ const delivery = (type === 'delivery');
const id = this.safeString (market, 'symbol');
const lowercaseId = this.safeStringLower (market, 'symbol');
- const baseId = market['baseAsset'];
- const quoteId = market['quoteAsset'];
+ const baseId = this.safeString (market, 'baseAsset');
+ const quoteId = this.safeString (market, 'quoteAsset');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
- const symbol = base + '/' + quote;
- const filters = this.indexBy (market['filters'], 'filterType');
+ const parts = id.split ('_');
+ const lastPart = this.safeString (parts, 1);
+ const idSymbol = (delivery) && (lastPart !== 'PERP');
+ const symbol = idSymbol ? id : (base + '/' + quote);
+ const filters = this.safeValue (market, 'filters', []);
+ const filtersByType = this.indexBy (filters, 'filterType');
const precision = {
- 'base': market['baseAssetPrecision'],
- 'quote': market['quotePrecision'],
- 'amount': market['baseAssetPrecision'],
- 'price': market['quotePrecision'],
+ 'base': this.safeInteger (market, 'baseAssetPrecision'),
+ 'quote': this.safeInteger (market, 'quotePrecision'),
+ 'amount': this.safeInteger (market, 'baseAssetPrecision'),
+ 'price': this.safeInteger (market, 'quotePrecision'),
};
- const status = this.safeString (market, 'status');
+ const status = this.safeString2 (market, 'status', 'contractStatus');
const active = (status === 'TRADING');
+ const margin = this.safeValue (market, 'isMarginTradingAllowed', future || delivery);
const entry = {
'id': id,
'lowercaseId': lowercaseId,
@@ -498,9 +739,11 @@ module.exports = class binance extends Exchange {
'baseId': baseId,
'quoteId': quoteId,
'info': market,
- 'type': marketType,
+ 'type': type,
'spot': spot,
+ 'margin': margin,
'future': future,
+ 'delivery': delivery,
'active': active,
'precision': precision,
'limits': {
@@ -518,8 +761,8 @@ module.exports = class binance extends Exchange {
},
},
};
- if ('PRICE_FILTER' in filters) {
- const filter = filters['PRICE_FILTER'];
+ if ('PRICE_FILTER' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'PRICE_FILTER', {});
// PRICE_FILTER reports zero values for maxPrice
// since they updated filter types in November 2018
// https://github.com/ccxt/ccxt/issues/4286
@@ -534,8 +777,8 @@ module.exports = class binance extends Exchange {
}
entry['precision']['price'] = this.precisionFromString (filter['tickSize']);
}
- if ('LOT_SIZE' in filters) {
- const filter = this.safeValue (filters, 'LOT_SIZE', {});
+ if ('LOT_SIZE' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'LOT_SIZE', {});
const stepSize = this.safeString (filter, 'stepSize');
entry['precision']['amount'] = this.precisionFromString (stepSize);
entry['limits']['amount'] = {
@@ -543,15 +786,16 @@ module.exports = class binance extends Exchange {
'max': this.safeFloat (filter, 'maxQty'),
};
}
- if ('MARKET_LOT_SIZE' in filters) {
- const filter = this.safeValue (filters, 'MARKET_LOT_SIZE', {});
+ if ('MARKET_LOT_SIZE' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'MARKET_LOT_SIZE', {});
entry['limits']['market'] = {
'min': this.safeFloat (filter, 'minQty'),
'max': this.safeFloat (filter, 'maxQty'),
};
}
- if ('MIN_NOTIONAL' in filters) {
- entry['limits']['cost']['min'] = this.safeFloat (filters['MIN_NOTIONAL'], 'minNotional');
+ if ('MIN_NOTIONAL' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'MIN_NOTIONAL', {});
+ entry['limits']['cost']['min'] = this.safeFloat (filter, 'minNotional');
}
result.push (entry);
}
@@ -583,7 +827,18 @@ module.exports = class binance extends Exchange {
await this.loadMarkets ();
const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
- const method = (type === 'spot') ? 'privateGetAccount' : 'fapiPrivateGetAccount';
+ let method = 'privateGetAccount';
+ if (type === 'future') {
+ const options = this.safeValue (this.options, 'future', {});
+ const fetchBalanceOptions = this.safeValue (options, 'fetchBalance', {});
+ method = this.safeString (fetchBalanceOptions, 'method', 'fapiPrivateV2GetAccount');
+ } else if (type === 'delivery') {
+ const options = this.safeValue (this.options, 'delivery', {});
+ const fetchBalanceOptions = this.safeValue (options, 'fetchBalance', {});
+ method = this.safeString (fetchBalanceOptions, 'method', 'dapiPrivateGetAccount');
+ } else if (type === 'margin') {
+ method = 'sapiGetMarginAccount';
+ }
const query = this.omit (params, 'type');
const response = await this[method] (query);
//
@@ -604,8 +859,27 @@ module.exports = class binance extends Exchange {
// ]
// }
//
+ // margin
+ //
+ // {
+ // "borrowEnabled":true,
+ // "marginLevel":"999.00000000",
+ // "totalAssetOfBtc":"0.00000000",
+ // "totalLiabilityOfBtc":"0.00000000",
+ // "totalNetAssetOfBtc":"0.00000000",
+ // "tradeEnabled":true,
+ // "transferEnabled":true,
+ // "userAssets":[
+ // {"asset":"MATIC","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"},
+ // {"asset":"VET","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"},
+ // {"asset":"USDT","borrowed":"0.00000000","free":"0.00000000","interest":"0.00000000","locked":"0.00000000","netAsset":"0.00000000"}
+ // ],
+ // }
+ //
// futures (fapi)
//
+ // fapiPrivateGetAccount
+ //
// {
// "feeTier":0,
// "canTrade":true,
@@ -645,9 +919,75 @@ module.exports = class binance extends Exchange {
// ]
// }
//
+ // fapiPrivateV2GetAccount
+ //
+ // {
+ // "feeTier":0,
+ // "canTrade":true,
+ // "canDeposit":true,
+ // "canWithdraw":true,
+ // "updateTime":0,
+ // "totalInitialMargin":"0.00000000",
+ // "totalMaintMargin":"0.00000000",
+ // "totalWalletBalance":"0.00000000",
+ // "totalUnrealizedProfit":"0.00000000",
+ // "totalMarginBalance":"0.00000000",
+ // "totalPositionInitialMargin":"0.00000000",
+ // "totalOpenOrderInitialMargin":"0.00000000",
+ // "totalCrossWalletBalance":"0.00000000",
+ // "totalCrossUnPnl":"0.00000000",
+ // "availableBalance":"0.00000000",
+ // "maxWithdrawAmount":"0.00000000",
+ // "assets":[
+ // {
+ // "asset":"BNB",
+ // "walletBalance":"0.01000000",
+ // "unrealizedProfit":"0.00000000",
+ // "marginBalance":"0.01000000",
+ // "maintMargin":"0.00000000",
+ // "initialMargin":"0.00000000",
+ // "positionInitialMargin":"0.00000000",
+ // "openOrderInitialMargin":"0.00000000",
+ // "maxWithdrawAmount":"0.01000000",
+ // "crossWalletBalance":"0.01000000",
+ // "crossUnPnl":"0.00000000",
+ // "availableBalance":"0.01000000"
+ // }
+ // ],
+ // "positions":[
+ // {
+ // "symbol":"BTCUSDT",
+ // "initialMargin":"0",
+ // "maintMargin":"0",
+ // "unrealizedProfit":"0.00000000",
+ // "positionInitialMargin":"0",
+ // "openOrderInitialMargin":"0",
+ // "leverage":"20",
+ // "isolated":false,
+ // "entryPrice":"0.00000",
+ // "maxNotional":"5000000",
+ // "positionSide":"BOTH"
+ // },
+ // ]
+ // }
+ //
+ // fapiPrivateV2GetBalance
+ //
+ // [
+ // {
+ // "accountAlias":"FzFzXquXXqoC",
+ // "asset":"BNB",
+ // "balance":"0.01000000",
+ // "crossWalletBalance":"0.01000000",
+ // "crossUnPnl":"0.00000000",
+ // "availableBalance":"0.01000000",
+ // "maxWithdrawAmount":"0.01000000"
+ // }
+ // ]
+ //
const result = { 'info': response };
- if (type === 'spot') {
- const balances = this.safeValue (response, 'balances', []);
+ if ((type === 'spot') || (type === 'margin')) {
+ const balances = this.safeValue2 (response, 'balances', 'userAssets', []);
for (let i = 0; i < balances.length; i++) {
const balance = balances[i];
const currencyId = this.safeString (balance, 'asset');
@@ -658,14 +998,18 @@ module.exports = class binance extends Exchange {
result[code] = account;
}
} else {
- const balances = this.safeValue (response, 'assets', []);
+ let balances = response;
+ if (!Array.isArray (response)) {
+ balances = this.safeValue (response, 'assets', []);
+ }
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.safeFloat (balance, 'availableBalance');
account['used'] = this.safeFloat (balance, 'initialMargin');
- account['total'] = this.safeFloat (balance, 'marginBalance');
+ account['total'] = this.safeFloat2 (balance, 'marginBalance', 'balance');
result[code] = account;
}
}
@@ -681,7 +1025,12 @@ module.exports = class binance extends Exchange {
if (limit !== undefined) {
request['limit'] = limit; // default 100, max 5000, see https://github.com/binance-exchange/binance-official-api-docs/blob/master/rest-api.md#order-book
}
- const method = market['spot'] ? 'publicGetDepth' : 'fapiPublicGetDepth';
+ let method = 'publicGetDepth';
+ if (market['future']) {
+ method = 'fapiPublicGetDepth';
+ } else if (market['delivery']) {
+ method = 'dapiPublicGetDepth';
+ }
const response = await this[method] (this.extend (request, params));
const orderbook = this.parseOrderBook (response);
orderbook['nonce'] = this.safeInteger (response, 'lastUpdateId');
@@ -689,15 +1038,34 @@ module.exports = class binance extends Exchange {
}
parseTicker (ticker, market = undefined) {
+ //
+ // {
+ // symbol: 'ETHBTC',
+ // priceChange: '0.00068700',
+ // priceChangePercent: '2.075',
+ // weightedAvgPrice: '0.03342681',
+ // prevClosePrice: '0.03310300',
+ // lastPrice: '0.03378900',
+ // lastQty: '0.07700000',
+ // bidPrice: '0.03378900',
+ // bidQty: '7.16800000',
+ // askPrice: '0.03379000',
+ // askQty: '24.00000000',
+ // openPrice: '0.03310200',
+ // highPrice: '0.03388900',
+ // lowPrice: '0.03306900',
+ // volume: '205478.41000000',
+ // quoteVolume: '6868.48826294',
+ // openTime: 1601469986932,
+ // closeTime: 1601556386932,
+ // firstId: 196098772,
+ // lastId: 196186315,
+ // count: 87544
+ // }
+ //
const timestamp = this.safeInteger (ticker, 'closeTime');
- let symbol = undefined;
const marketId = this.safeString (ticker, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const last = this.safeFloat (ticker, 'lastPrice');
return {
'symbol': symbol,
@@ -742,8 +1110,17 @@ module.exports = class binance extends Exchange {
const request = {
'symbol': market['id'],
};
- const method = market['spot'] ? 'publicGetTicker24hr' : 'fapiPublicGetTicker24hr';
+ let method = 'publicGetTicker24hr';
+ if (market['future']) {
+ method = 'fapiPublicGetTicker24hr';
+ } else if (market['delivery']) {
+ method = 'dapiPublicGetTicker24hr';
+ }
const response = await this[method] (this.extend (request, params));
+ if (Array.isArray (response)) {
+ const firstTicker = this.safeValue (response, 0, {});
+ return this.parseTicker (firstTicker, market);
+ }
return this.parseTicker (response, market);
}
@@ -760,19 +1137,53 @@ module.exports = class binance extends Exchange {
const defaultType = this.safeString2 (this.options, 'fetchBidsAsks', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
- const method = (type === 'spot') ? 'publicGetTickerBookTicker' : 'fapiPublicGetTickerBookTicker';
+ let method = undefined;
+ if (type === 'future') {
+ method = 'fapiPublicGetTickerBookTicker';
+ } else if (type === 'delivery') {
+ method = 'dapiPublicGetTickerBookTicker';
+ } else {
+ method = 'publicGetTickerBookTicker';
+ }
const response = await this[method] (query);
return this.parseTickers (response, symbols);
}
async fetchTickers (symbols = undefined, params = {}) {
await this.loadMarkets ();
- const method = this.options['fetchTickersMethod'];
- const response = await this[method] (params);
+ const defaultType = this.safeString2 (this.options, 'fetchTickers', 'defaultType', 'spot');
+ const type = this.safeString (params, 'type', defaultType);
+ const query = this.omit (params, 'type');
+ let defaultMethod = undefined;
+ if (type === 'future') {
+ defaultMethod = 'fapiPublicGetTicker24hr';
+ } else if (type === 'delivery') {
+ defaultMethod = 'dapiPublicGetTicker24hr';
+ } else {
+ defaultMethod = 'publicGetTicker24hr';
+ }
+ const method = this.safeString (this.options, 'fetchTickersMethod', defaultMethod);
+ const response = await this[method] (query);
return this.parseTickers (response, symbols);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591478520000,
+ // "0.02501300",
+ // "0.02501800",
+ // "0.02500000",
+ // "0.02500000",
+ // "22.19000000",
+ // 1591478579999,
+ // "0.55490906",
+ // 40,
+ // "10.92900000",
+ // "0.27336462",
+ // "0"
+ // ]
+ //
return [
this.safeInteger (ohlcv, 0),
this.safeFloat (ohlcv, 1),
@@ -796,8 +1207,20 @@ module.exports = class binance extends Exchange {
if (limit !== undefined) {
request['limit'] = limit; // default == max == 500
}
- const method = market['spot'] ? 'publicGetKlines' : 'fapiPublicGetKlines';
+ let method = 'publicGetKlines';
+ if (market['future']) {
+ method = 'fapiPublicGetKlines';
+ } else if (market['delivery']) {
+ method = 'dapiPublicGetKlines';
+ }
const response = await this[method] (this.extend (request, params));
+ //
+ // [
+ // [1591478520000,"0.02501300","0.02501800","0.02500000","0.02500000","22.19000000",1591478579999,"0.55490906",40,"10.92900000","0.27336462","0"],
+ // [1591478580000,"0.02499600","0.02500900","0.02499400","0.02500300","21.34700000",1591478639999,"0.53370468",24,"7.53800000","0.18850725","0"],
+ // [1591478640000,"0.02500800","0.02501100","0.02500300","0.02500800","154.14200000",1591478699999,"3.85405839",97,"5.32300000","0.13312641","0"],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -899,14 +1322,8 @@ module.exports = class binance extends Exchange {
if ('isMaker' in trade) {
takerOrMaker = trade['isMaker'] ? 'maker' : 'taker';
}
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (trade, 'symbol');
- market = this.safeValue (this.markets_by_id, marketId);
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (trade, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
let cost = undefined;
if ((price !== undefined) && (amount !== undefined)) {
cost = price * amount;
@@ -941,7 +1358,14 @@ module.exports = class binance extends Exchange {
const defaultType = this.safeString2 (this.options, 'fetchTrades', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
- const defaultMethod = (type === 'future') ? 'fapiPublicGetTrades' : 'publicGetTrades';
+ let defaultMethod = undefined;
+ if (type === 'future') {
+ defaultMethod = 'fapiPublicGetAggTrades';
+ } else if (type === 'delivery') {
+ defaultMethod = 'dapiPublicGetAggTrades';
+ } else {
+ defaultMethod = 'publicGetAggTrades';
+ }
let method = this.safeString (this.options, 'fetchTradesMethod', defaultMethod);
if (method === 'publicGetAggTrades') {
if (since !== undefined) {
@@ -952,9 +1376,15 @@ module.exports = class binance extends Exchange {
}
if (type === 'future') {
method = 'fapiPublicGetAggTrades';
+ } else if (type === 'delivery') {
+ method = 'dapiPublicGetAggTrades';
+ }
+ } else if (method === 'publicGetHistoricalTrades') {
+ if (type === 'future') {
+ method = 'fapiPublicGetHistoricalTrades';
+ } else if (type === 'delivery') {
+ method = 'dapiPublicGetHistoricalTrades';
}
- } else if ((method === 'publicGetHistoricalTrades') && (type === 'future')) {
- method = 'fapiPublicGetHistoricalTrades';
}
if (limit !== undefined) {
request['limit'] = limit; // default = 500, maximum = 1000
@@ -1056,14 +1486,8 @@ module.exports = class binance extends Exchange {
// }
//
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
let timestamp = undefined;
if ('time' in order) {
timestamp = this.safeInteger (order, 'time');
@@ -1140,6 +1564,7 @@ module.exports = class binance extends Exchange {
}
}
const clientOrderId = this.safeString (order, 'clientOrderId');
+ const timeInForce = this.safeString (order, 'timeInForce');
return {
'info': order,
'id': id,
@@ -1149,6 +1574,7 @@ module.exports = class binance extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
'amount': amount,
@@ -1165,14 +1591,25 @@ module.exports = class binance extends Exchange {
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
+ const defaultType = this.safeString2 (this.options, 'createOrder', 'defaultType', market['type']);
+ const orderType = this.safeString (params, 'type', defaultType);
+ const clientOrderId = this.safeString2 (params, 'newClientOrderId', 'clientOrderId');
+ params = this.omit (params, [ 'type', 'newClientOrderId', 'clientOrderId' ]);
+ let method = 'privatePostOrder';
+ if (orderType === 'future') {
+ method = 'fapiPrivatePostOrder';
+ } else if (orderType === 'delivery') {
+ method = 'dapiPrivatePostOrder';
+ } else if (orderType === 'margin') {
+ method = 'sapiPostMarginOrder';
+ }
// the next 5 lines are added to support for testing orders
- let method = market['spot'] ? 'privatePostOrder' : 'fapiPrivatePostOrder';
if (market['spot']) {
const test = this.safeValue (params, 'test', false);
if (test) {
method += 'Test';
- params = this.omit (params, 'test');
}
+ params = this.omit (params, 'test');
}
const uppercaseType = type.toUpperCase ();
const validOrderTypes = this.safeValue (market['info'], 'orderTypes');
@@ -1184,45 +1621,90 @@ module.exports = class binance extends Exchange {
'type': uppercaseType,
'side': side.toUpperCase (),
};
- if (uppercaseType === 'MARKET') {
- const quoteOrderQty = this.safeFloat (params, 'quoteOrderQty');
- const precision = market['precision']['price'];
- if (quoteOrderQty !== undefined) {
- request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQty, TRUNCATE, precision, this.precisionMode);
- params = this.omit (params, 'quoteOrderQty');
- } else if (price !== undefined) {
- request['quoteOrderQty'] = this.decimalToPrecision (amount * price, TRUNCATE, precision, this.precisionMode);
- } else {
- request['quantity'] = this.amountToPrecision (symbol, amount);
- }
- } else {
- request['quantity'] = this.amountToPrecision (symbol, amount);
+ if (clientOrderId !== undefined) {
+ request['newClientOrderId'] = clientOrderId;
}
if (market['spot']) {
request['newOrderRespType'] = this.safeValue (this.options['newOrderRespType'], type, 'RESULT'); // 'ACK' for order id, 'RESULT' for full order or 'FULL' for order with fills
}
+ // additional required fields depending on the order type
let timeInForceIsRequired = false;
let priceIsRequired = false;
let stopPriceIsRequired = false;
- if (uppercaseType === 'LIMIT') {
+ let quantityIsRequired = false;
+ //
+ // spot/margin
+ //
+ // LIMIT timeInForce, quantity, price
+ // MARKET quantity or quoteOrderQty
+ // STOP_LOSS quantity, stopPrice
+ // STOP_LOSS_LIMIT timeInForce, quantity, price, stopPrice
+ // TAKE_PROFIT quantity, stopPrice
+ // TAKE_PROFIT_LIMIT timeInForce, quantity, price, stopPrice
+ // LIMIT_MAKER quantity, price
+ //
+ // futures
+ //
+ // LIMIT timeInForce, quantity, price
+ // MARKET quantity
+ // STOP/TAKE_PROFIT quantity, price, stopPrice
+ // STOP_MARKET stopPrice
+ // TAKE_PROFIT_MARKET stopPrice
+ // TRAILING_STOP_MARKET callbackRate
+ //
+ if (uppercaseType === 'MARKET') {
+ const quoteOrderQty = this.safeValue (this.options, 'quoteOrderQty', false);
+ if (quoteOrderQty) {
+ const quoteOrderQty = this.safeFloat (params, 'quoteOrderQty');
+ const precision = market['precision']['price'];
+ if (quoteOrderQty !== undefined) {
+ request['quoteOrderQty'] = this.decimalToPrecision (quoteOrderQty, TRUNCATE, precision, this.precisionMode);
+ params = this.omit (params, 'quoteOrderQty');
+ } else if (price !== undefined) {
+ request['quoteOrderQty'] = this.decimalToPrecision (amount * price, TRUNCATE, precision, this.precisionMode);
+ } else {
+ quantityIsRequired = true;
+ }
+ } else {
+ quantityIsRequired = true;
+ }
+ } else if (uppercaseType === 'LIMIT') {
priceIsRequired = true;
timeInForceIsRequired = true;
+ quantityIsRequired = true;
} else if ((uppercaseType === 'STOP_LOSS') || (uppercaseType === 'TAKE_PROFIT')) {
stopPriceIsRequired = true;
+ quantityIsRequired = true;
if (market['future']) {
priceIsRequired = true;
}
} else if ((uppercaseType === 'STOP_LOSS_LIMIT') || (uppercaseType === 'TAKE_PROFIT_LIMIT')) {
+ quantityIsRequired = true;
stopPriceIsRequired = true;
priceIsRequired = true;
timeInForceIsRequired = true;
} else if (uppercaseType === 'LIMIT_MAKER') {
priceIsRequired = true;
+ quantityIsRequired = true;
} else if (uppercaseType === 'STOP') {
+ quantityIsRequired = true;
stopPriceIsRequired = true;
priceIsRequired = true;
- } else if (uppercaseType === 'STOP_MARKET') {
+ } else if ((uppercaseType === 'STOP_MARKET') || (uppercaseType === 'TAKE_PROFIT_MARKET')) {
+ const closePosition = this.safeValue (params, 'closePosition');
+ if (closePosition === undefined) {
+ quantityIsRequired = true;
+ }
stopPriceIsRequired = true;
+ } else if (uppercaseType === 'TRAILING_STOP_MARKET') {
+ quantityIsRequired = true;
+ const callbackRate = this.safeFloat (params, 'callbackRate');
+ if (callbackRate === undefined) {
+ throw new InvalidOrder (this.id + ' createOrder method requires a callbackRate extra param for a ' + type + ' order');
+ }
+ }
+ if (quantityIsRequired) {
+ request['quantity'] = this.amountToPrecision (symbol, amount);
}
if (priceIsRequired) {
if (price === undefined) {
@@ -1252,17 +1734,27 @@ module.exports = class binance extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
- const method = market['spot'] ? 'privateGetOrder' : 'fapiPrivateGetOrder';
+ const defaultType = this.safeString2 (this.options, 'fetchOrder', 'defaultType', market['type']);
+ const type = this.safeString (params, 'type', defaultType);
+ let method = 'privateGetOrder';
+ if (type === 'future') {
+ method = 'fapiPrivateGetOrder';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateGetOrder';
+ } else if (type === 'margin') {
+ method = 'sapiGetMarginOrder';
+ }
const request = {
'symbol': market['id'],
};
- const origClientOrderId = this.safeValue (params, 'origClientOrderId');
- if (origClientOrderId !== undefined) {
- request['origClientOrderId'] = origClientOrderId;
+ const clientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['origClientOrderId'] = clientOrderId;
} else {
request['orderId'] = parseInt (id);
}
- const response = await this[method] (this.extend (request, params));
+ const query = this.omit (params, [ 'type', 'clientOrderId', 'origClientOrderId' ]);
+ const response = await this[method] (this.extend (request, query));
return this.parseOrder (response, market);
}
@@ -1272,6 +1764,16 @@ module.exports = class binance extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
+ const defaultType = this.safeString2 (this.options, 'fetchOrders', 'defaultType', market['type']);
+ const type = this.safeString (params, 'type', defaultType);
+ let method = 'privateGetAllOrders';
+ if (type === 'future') {
+ method = 'fapiPrivateGetAllOrders';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateGetAllOrders';
+ } else if (type === 'margin') {
+ method = 'sapiGetMarginAllOrders';
+ }
const request = {
'symbol': market['id'],
};
@@ -1281,10 +1783,11 @@ module.exports = class binance extends Exchange {
if (limit !== undefined) {
request['limit'] = limit;
}
- const method = market['spot'] ? 'privateGetAllOrders' : 'fapiPrivateGetAllOrders';
- const response = await this[method] (this.extend (request, params));
+ const query = this.omit (params, 'type');
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
//
- // Spot:
// [
// {
// "symbol": "LTCBTC",
@@ -1306,7 +1809,8 @@ module.exports = class binance extends Exchange {
// }
// ]
//
- // Futures:
+ // futures
+ //
// [
// {
// "symbol": "BTCUSDT",
@@ -1337,8 +1841,9 @@ module.exports = class binance extends Exchange {
if (symbol !== undefined) {
market = this.market (symbol);
request['symbol'] = market['id'];
- type = market['type'];
- query = params;
+ const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', market['type']);
+ type = this.safeString (params, 'type', defaultType);
+ query = this.omit (params, 'type');
} else if (this.options['warnOnFetchOpenOrdersWithoutSymbol']) {
const symbols = this.symbols;
const numSymbols = symbols.length;
@@ -1349,7 +1854,14 @@ module.exports = class binance extends Exchange {
type = this.safeString (params, 'type', defaultType);
query = this.omit (params, 'type');
}
- const method = (type === 'spot') ? 'privateGetOpenOrders' : 'fapiPrivateGetOpenOrders';
+ let method = 'privateGetOpenOrders';
+ if (type === 'future') {
+ method = 'fapiPrivateGetOpenOrders';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateGetOpenOrders';
+ } else if (type === 'margin') {
+ method = 'sapiGetMarginOpenOrders';
+ }
const response = await this[method] (this.extend (request, query));
return this.parseOrders (response, market, since, limit);
}
@@ -1365,8 +1877,10 @@ module.exports = class binance extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
+ const defaultType = this.safeString2 (this.options, 'fetchOpenOrders', 'defaultType', market['type']);
+ const type = this.safeString (params, 'type', defaultType);
// https://github.com/ccxt/ccxt/issues/6507
- const origClientOrderId = this.safeValue (params, 'origClientOrderId');
+ const origClientOrderId = this.safeValue2 (params, 'origClientOrderId', 'clientOrderId');
const request = {
'symbol': market['id'],
// 'orderId': parseInt (id),
@@ -1377,8 +1891,16 @@ module.exports = class binance extends Exchange {
} else {
request['origClientOrderId'] = origClientOrderId;
}
- const method = market['spot'] ? 'privateDeleteOrder' : 'fapiPrivateDeleteOrder';
- const response = await this[method] (this.extend (request, params));
+ let method = 'privateDeleteOrder';
+ if (type === 'future') {
+ method = 'fapiPrivateDeleteOrder';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateDeleteOrder';
+ } else if (type === 'margin') {
+ method = 'sapiDeleteMarginOrder';
+ }
+ const query = this.omit (params, [ 'type', 'origClientOrderId', 'clientOrderId' ]);
+ const response = await this[method] (this.extend (request, query));
return this.parseOrder (response);
}
@@ -1394,7 +1916,12 @@ module.exports = class binance extends Exchange {
const defaultType = this.safeString2 (this.options, 'cancelAllOrders', 'defaultType', 'spot');
const type = this.safeString (params, 'type', defaultType);
const query = this.omit (params, 'type');
- const method = (type === 'spot') ? 'privateDeleteOpenOrders' : 'fapiPrivateDeleteAllOpenOrders';
+ let method = 'privateDeleteOpenOrders';
+ if (type === 'future') {
+ method = 'fapiPrivateDeleteAllOpenOrders';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateDeleteAllOpenOrders';
+ }
const response = await this[method] (this.extend (request, query));
if (Array.isArray (response)) {
return this.parseOrders (response, market);
@@ -1403,13 +1930,73 @@ module.exports = class binance extends Exchange {
}
}
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.fetchBalance (params);
+ const info = this.safeValue (response, 'info', {});
+ //
+ // futures, delivery
+ //
+ // {
+ // "feeTier":0,
+ // "canTrade":true,
+ // "canDeposit":true,
+ // "canWithdraw":true,
+ // "updateTime":0,
+ // "assets":[
+ // {
+ // "asset":"ETH",
+ // "walletBalance":"0.09886711",
+ // "unrealizedProfit":"0.00000000",
+ // "marginBalance":"0.09886711",
+ // "maintMargin":"0.00000000",
+ // "initialMargin":"0.00000000",
+ // "positionInitialMargin":"0.00000000",
+ // "openOrderInitialMargin":"0.00000000",
+ // "maxWithdrawAmount":"0.09886711",
+ // "crossWalletBalance":"0.09886711",
+ // "crossUnPnl":"0.00000000",
+ // "availableBalance":"0.09886711"
+ // }
+ // ],
+ // "positions":[
+ // {
+ // "symbol":"BTCUSD_201225",
+ // "initialMargin":"0",
+ // "maintMargin":"0",
+ // "unrealizedProfit":"0.00000000",
+ // "positionInitialMargin":"0",
+ // "openOrderInitialMargin":"0",
+ // "leverage":"20",
+ // "isolated":false,
+ // "positionSide":"BOTH",
+ // "entryPrice":"0.00000000",
+ // "maxQty":"250", // "maxNotional" on futures
+ // },
+ // ]
+ // }
+ //
+ const positions = this.safeValue2 (info, 'positions', 'userAssets', []);
+ // todo unify parsePosition/parsePositions
+ return positions;
+ }
+
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
if (symbol === undefined) {
throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
- const method = market['spot'] ? 'privateGetMyTrades' : 'fapiPrivateGetUserTrades';
+ const type = this.safeValue (params, 'type', market['type']);
+ let method = undefined;
+ if (type === 'spot') {
+ method = 'privateGetMyTrades';
+ } else if (type === 'future') {
+ method = 'fapiPrivateGetUserTrades';
+ } else if (type === 'delivery') {
+ method = 'dapiPrivateGetUserTrades';
+ }
+ params = this.omit (params, 'type');
const request = {
'symbol': market['id'],
};
@@ -1422,6 +2009,7 @@ module.exports = class binance extends Exchange {
const response = await this[method] (this.extend (request, params));
//
// spot trade
+ //
// [
// {
// "symbol": "BNBBTC",
@@ -1459,6 +2047,7 @@ module.exports = class binance extends Exchange {
// "time": 1569514978020
// }
// ]
+ //
return this.parseTrades (response, market, since, limit);
}
@@ -1714,6 +2303,7 @@ module.exports = class binance extends Exchange {
if (feeCost !== undefined) {
fee = { 'currency': code, 'cost': feeCost };
}
+ const updated = this.safeInteger (transaction, 'successTime');
return {
'info': transaction,
'id': id,
@@ -1721,12 +2311,16 @@ module.exports = class binance extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'address': address,
+ 'addressTo': address,
+ 'addressFrom': undefined,
'tag': tag,
+ 'tagTo': tag,
+ 'tagFrom': undefined,
'type': type,
'amount': amount,
'currency': code,
'status': status,
- 'updated': undefined,
+ 'updated': updated,
'fee': fee,
};
}
@@ -1747,7 +2341,7 @@ module.exports = class binance extends Exchange {
this.checkAddress (address);
return {
'currency': code,
- 'address': this.checkAddress (address),
+ 'address': address,
'tag': tag,
'info': response,
};
@@ -1824,11 +2418,7 @@ module.exports = class binance extends Exchange {
// }
//
const marketId = this.safeString (fee, 'symbol');
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- const market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId);
return {
'info': fee,
'symbol': symbol,
@@ -1887,6 +2477,9 @@ module.exports = class binance extends Exchange {
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ if (!(api in this.urls['api'])) {
+ throw new NotSupported (this.id + ' does not have a testnet/sandbox URL for ' + api + ' endpoints');
+ }
let url = this.urls['api'][api];
url += '/' + path;
if (api === 'wapi') {
@@ -1913,23 +2506,24 @@ module.exports = class binance extends Exchange {
throw new AuthenticationError (this.id + ' userDataStream endpoint requires `apiKey` credential');
}
}
- if ((api === 'private') || (api === 'sapi') || (api === 'wapi' && path !== 'systemStatus') || (api === 'fapiPrivate')) {
+ if ((api === 'private') || (api === 'sapi') || (api === 'wapi' && path !== 'systemStatus') || (api === 'dapiPrivate') || (api === 'fapiPrivate') || (api === 'fapiPrivateV2')) {
this.checkRequiredCredentials ();
let query = undefined;
+ const recvWindow = this.safeInteger (this.options, 'recvWindow', 5000);
if ((api === 'sapi') && (path === 'asset/dust')) {
query = this.urlencodeWithArrayRepeat (this.extend ({
'timestamp': this.nonce (),
- 'recvWindow': this.options['recvWindow'],
+ 'recvWindow': recvWindow,
}, params));
} else if (path === 'batchOrders') {
query = this.rawencode (this.extend ({
'timestamp': this.nonce (),
- 'recvWindow': this.options['recvWindow'],
+ 'recvWindow': recvWindow,
}, params));
} else {
query = this.urlencode (this.extend ({
'timestamp': this.nonce (),
- 'recvWindow': this.options['recvWindow'],
+ 'recvWindow': recvWindow,
}, params));
}
const signature = this.hmac (this.encode (query), this.encode (this.secret));
@@ -1974,52 +2568,52 @@ module.exports = class binance extends Exchange {
throw new InvalidOrder (this.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid float value in general, use this.priceToPrecision (symbol, amount) ' + body);
}
}
- if (body.length > 0) {
- if (body[0] === '{') {
- // check success value for wapi endpoints
- // response in format {'msg': 'The coin does not exist.', 'success': true/false}
- const success = this.safeValue (response, 'success', true);
- if (!success) {
- const message = this.safeString (response, 'msg');
- let parsedMessage = undefined;
- if (message !== undefined) {
- try {
- parsedMessage = JSON.parse (message);
- } catch (e) {
- // do nothing
- parsedMessage = undefined;
- }
- if (parsedMessage !== undefined) {
- response = parsedMessage;
- }
- }
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ // check success value for wapi endpoints
+ // response in format {'msg': 'The coin does not exist.', 'success': true/false}
+ const success = this.safeValue (response, 'success', true);
+ if (!success) {
+ const message = this.safeString (response, 'msg');
+ let parsedMessage = undefined;
+ if (message !== undefined) {
+ try {
+ parsedMessage = JSON.parse (message);
+ } catch (e) {
+ // do nothing
+ parsedMessage = undefined;
}
- const message = this.safeString (response, 'msg');
- if (message !== undefined) {
- this.throwExactlyMatchedException (this.exceptions, message, this.id + ' ' + message);
- }
- // checks against error codes
- const error = this.safeString (response, 'code');
- if (error !== undefined) {
- // https://github.com/ccxt/ccxt/issues/6501
- if (error === '200') {
- return;
- }
- // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
- // despite that their message is very confusing, it is raised by Binance
- // on a temporary ban, the API key is valid, but disabled for a while
- if ((error === '-2015') && this.options['hasAlreadyAuthenticatedSuccessfully']) {
- throw new DDoSProtection (this.id + ' temporary banned: ' + body);
- }
- const feedback = this.id + ' ' + body;
- this.throwExactlyMatchedException (this.exceptions, error, feedback);
- throw new ExchangeError (feedback);
- }
- if (!success) {
- throw new ExchangeError (this.id + ' ' + body);
+ if (parsedMessage !== undefined) {
+ response = parsedMessage;
}
}
}
+ const message = this.safeString (response, 'msg');
+ if (message !== undefined) {
+ this.throwExactlyMatchedException (this.exceptions, message, this.id + ' ' + message);
+ }
+ // checks against error codes
+ const error = this.safeString (response, 'code');
+ if (error !== undefined) {
+ // https://github.com/ccxt/ccxt/issues/6501
+ // https://github.com/ccxt/ccxt/issues/7742
+ if ((error === '200') || (error === '0')) {
+ return;
+ }
+ // a workaround for {"code":-2015,"msg":"Invalid API-key, IP, or permissions for action."}
+ // despite that their message is very confusing, it is raised by Binance
+ // on a temporary ban, the API key is valid, but disabled for a while
+ if ((error === '-2015') && this.options['hasAlreadyAuthenticatedSuccessfully']) {
+ throw new DDoSProtection (this.id + ' temporary banned: ' + body);
+ }
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions, error, feedback);
+ throw new ExchangeError (feedback);
+ }
+ if (!success) {
+ throw new ExchangeError (this.id + ' ' + body);
+ }
}
async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
diff --git a/TaskServer/node_modules/ccxt/js/binanceus.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/binanceus.js
similarity index 95%
rename from TaskServer/node_modules/ccxt/js/binanceus.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/binanceus.js
index aafd7745e..c35f3f3e4 100644
--- a/TaskServer/node_modules/ccxt/js/binanceus.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/binanceus.js
@@ -37,6 +37,9 @@ module.exports = class binanceus extends binance {
'maker': 0.001, // 0.1% trading fee, zero fees for all trading pairs before November 1
},
},
+ 'options': {
+ 'quoteOrderQty': false,
+ },
});
}
};
diff --git a/TaskServer/node_modules/ccxt/js/bit2c.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bit2c.js
similarity index 88%
rename from TaskServer/node_modules/ccxt/js/bit2c.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bit2c.js
index d6b41b0d3..f09a98746 100644
--- a/TaskServer/node_modules/ccxt/js/bit2c.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bit2c.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ArgumentsRequired, ExchangeError } = require ('./base/errors');
+const { ArgumentsRequired, ExchangeError, InvalidNonce, AuthenticationError, PermissionDenied } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -15,9 +15,15 @@ module.exports = class bit2c extends Exchange {
'countries': [ 'IL' ], // Israel
'rateLimit': 3000,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27766119-3593220e-5ece-11e7-8b3a-5a041f6bcc3f.jpg',
@@ -80,11 +86,18 @@ module.exports = class bit2c extends Exchange {
},
},
'options': {
- 'fetchTradesMethod': 'public_get_exchanges_pair_lasttrades',
+ 'fetchTradesMethod': 'public_get_exchanges_pair_trades',
},
'exceptions': {
- // { "error" : "Please provide valid APIkey" }
- // { "error" : "Please provide valid nonce in Request UInt64.TryParse failed for nonce :" }
+ 'exact': {
+ 'Please provide valid APIkey': AuthenticationError, // { "error" : "Please provide valid APIkey" }
+ },
+ 'broad': {
+ // { "error": "Please provide valid nonce in Request Nonce (1598218490) is not bigger than last nonce (1598218490)."}
+ // { "error": "Please provide valid nonce in Request UInt64.TryParse failed for nonce :" }
+ 'Please provide valid nonce': InvalidNonce,
+ 'please approve new terms of use on site': PermissionDenied, // { "error" : "please approve new terms of use on site." }
+ },
},
});
}
@@ -204,6 +217,12 @@ module.exports = class bit2c extends Exchange {
const request = {
'pair': market['id'],
};
+ if (since !== undefined) {
+ request['date'] = parseInt (since);
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // max 100000
+ }
const response = await this[method] (this.extend (request, params));
if (typeof response === 'string') {
throw new ExchangeError (response);
@@ -286,8 +305,10 @@ module.exports = class bit2c extends Exchange {
'status': status,
'symbol': symbol,
'type': undefined,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': undefined,
'remaining': undefined,
@@ -411,10 +432,27 @@ module.exports = class bit2c extends Exchange {
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'key': this.apiKey,
- 'sign': this.decode (signature),
+ 'sign': signature,
};
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
+
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ //
+ // { "error" : "please approve new terms of use on site." }
+ // { "error": "Please provide valid nonce in Request Nonce (1598218490) is not bigger than last nonce (1598218490)."}
+ //
+ const error = this.safeString (response, 'error');
+ if (error !== undefined) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], error, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], error, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
};
diff --git a/TaskServer/node_modules/ccxt/js/bitbank.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitbank.js
similarity index 85%
rename from TaskServer/node_modules/ccxt/js/bitbank.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitbank.js
index 8b8f35684..722f16be6 100644
--- a/TaskServer/node_modules/ccxt/js/bitbank.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitbank.js
@@ -15,10 +15,17 @@ module.exports = class bitbank extends Exchange {
'countries': [ 'JP' ],
'version': 'v1',
'has': {
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchDepositAddress': true,
+ 'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
- 'fetchMyTrades': true,
- 'fetchDepositAddress': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'timeframes': {
@@ -78,7 +85,11 @@ module.exports = class bitbank extends Exchange {
'ETH/BTC': { 'id': 'eth_btc', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC', 'baseId': 'eth', 'quoteId': 'btc' },
'LTC/BTC': { 'id': 'ltc_btc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'baseId': 'ltc', 'quoteId': 'btc' },
'XRP/JPY': { 'id': 'xrp_jpy', 'symbol': 'XRP/JPY', 'base': 'XRP', 'quote': 'JPY', 'baseId': 'xrp', 'quoteId': 'jpy' },
+ 'XLM/JPY': { 'id': 'xlm_jpy', 'symbol': 'XLM/JPY', 'base': 'XLM', 'quote': 'JPY', 'baseId': 'xlm', 'quoteId': 'jpy' },
'BTC/JPY': { 'id': 'btc_jpy', 'symbol': 'BTC/JPY', 'base': 'BTC', 'quote': 'JPY', 'baseId': 'btc', 'quoteId': 'jpy' },
+ 'ETH/JPY': { 'id': 'eth_jpy', 'symbol': 'ETH/JPY', 'base': 'ETH', 'quote': 'JPY', 'baseId': 'eth', 'quoteId': 'jpy' },
+ 'LTC/JPY': { 'id': 'ltc_jpy', 'symbol': 'LTC/JPY', 'base': 'LTC', 'quote': 'JPY', 'baseId': 'ltc', 'quoteId': 'jpy' },
+ 'XRP/BTC': { 'id': 'xrp_btc', 'symbol': 'XRP/BTC', 'base': 'XRP', 'quote': 'BTC', 'baseId': 'xrp', 'quoteId': 'btc' },
},
'fees': {
'trading': {
@@ -159,7 +170,8 @@ module.exports = class bitbank extends Exchange {
'pair': market['id'],
};
const response = await this.publicGetPairTicker (this.extend (request, params));
- return this.parseTicker (response['data'], market);
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTicker (data, market);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -226,17 +238,29 @@ module.exports = class bitbank extends Exchange {
'pair': market['id'],
};
const response = await this.publicGetPairTransactions (this.extend (request, params));
- return this.parseTrades (response['data']['transactions'], market, since, limit);
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'transactions', []);
+ return this.parseTrades (trades, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // "0.02501786",
+ // "0.02501786",
+ // "0.02501786",
+ // "0.02501786",
+ // "0.0000",
+ // 1591488000000
+ // ]
+ //
return [
- ohlcv[5],
- parseFloat (ohlcv[0]),
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
+ this.safeInteger (ohlcv, 5),
+ this.safeFloat (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
];
}
@@ -252,7 +276,28 @@ module.exports = class bitbank extends Exchange {
'yyyymmdd': date.join (''),
};
const response = await this.publicGetPairCandlestickCandletypeYyyymmdd (this.extend (request, params));
- const ohlcv = this.safeValue (response['data']['candlestick'][0], 'ohlcv');
+ //
+ // {
+ // "success":1,
+ // "data":{
+ // "candlestick":[
+ // {
+ // "type":"5min",
+ // "ohlcv":[
+ // ["0.02501786","0.02501786","0.02501786","0.02501786","0.0000",1591488000000],
+ // ["0.02501747","0.02501953","0.02501747","0.02501953","0.3017",1591488300000],
+ // ["0.02501762","0.02501762","0.02500392","0.02500392","0.1500",1591488600000],
+ // ]
+ // }
+ // ],
+ // "timestamp":1591508668190
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const candlestick = this.safeValue (data, 'candlestick', []);
+ const first = this.safeValue (candlestick, 0, {});
+ const ohlcv = this.safeValue (first, 'ohlcv', []);
return this.parseOHLCVs (ohlcv, market, timeframe, since, limit);
}
@@ -260,9 +305,10 @@ module.exports = class bitbank extends Exchange {
await this.loadMarkets ();
const response = await this.privateGetUserAssets (params);
const result = { 'info': response };
- const balances = response['data']['assets'];
- for (let i = 0; i < balances.length; i++) {
- const balance = balances[i];
+ const data = this.safeValue (response, 'data', {});
+ const assets = this.safeValue (data, 'assets', []);
+ for (let i = 0; i < assets.length; i++) {
+ const balance = assets[i];
const currencyId = this.safeString (balance, 'asset');
const code = this.safeCurrencyCode (currencyId);
const account = {
@@ -320,8 +366,10 @@ module.exports = class bitbank extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -347,10 +395,8 @@ module.exports = class bitbank extends Exchange {
'type': type,
};
const response = await this.privatePostUserSpotOrder (this.extend (request, params));
- const order = this.parseOrder (response['data'], market);
- const id = order['id'];
- this.orders[id] = order;
- return order;
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -361,7 +407,8 @@ module.exports = class bitbank extends Exchange {
'pair': market['id'],
};
const response = await this.privatePostUserSpotCancelOrder (this.extend (request, params));
- return response['data'];
+ const data = this.safeValue (response, 'data');
+ return data;
}
async fetchOrder (id, symbol = undefined, params = {}) {
@@ -372,7 +419,8 @@ module.exports = class bitbank extends Exchange {
'pair': market['id'],
};
const response = await this.privateGetUserSpotOrder (this.extend (request, params));
- return this.parseOrder (response['data']);
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -388,7 +436,9 @@ module.exports = class bitbank extends Exchange {
request['since'] = parseInt (since / 1000);
}
const response = await this.privateGetUserSpotActiveOrders (this.extend (request, params));
- return this.parseOrders (response['data']['orders'], market, since, limit);
+ const data = this.safeValue (response, 'data', {});
+ const orders = this.safeValue (data, 'orders', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -408,7 +458,9 @@ module.exports = class bitbank extends Exchange {
request['since'] = parseInt (since / 1000);
}
const response = await this.privateGetUserSpotTradeHistory (this.extend (request, params));
- return this.parseTrades (response['data']['trades'], market, since, limit);
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'trades', []);
+ return this.parseTrades (trades, market, since, limit);
}
async fetchDepositAddress (code, params = {}) {
@@ -418,9 +470,11 @@ module.exports = class bitbank extends Exchange {
'asset': currency['id'],
};
const response = await this.privateGetUserWithdrawalAccount (this.extend (request, params));
+ const data = this.safeValue (response, 'data', {});
// Not sure about this if there could be more than one account...
- const accounts = response['data']['accounts'];
- const address = this.safeString (accounts[0], 'address');
+ const accounts = this.safeValue (data, 'accounts', []);
+ const firstAccount = this.safeValue (accounts, 0, {});
+ const address = this.safeString (firstAccount, 'address');
return {
'currency': currency,
'address': address,
@@ -440,7 +494,8 @@ module.exports = class bitbank extends Exchange {
'amount': amount,
};
const response = await this.privatePostUserRequestWithdrawal (this.extend (request, params));
- const txid = this.safeString (response['data'], 'txid');
+ const data = this.safeValue (response, 'data', {});
+ const txid = this.safeString (data, 'txid');
return {
'info': response,
'id': txid,
diff --git a/TaskServer/node_modules/ccxt/js/bitbay.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitbay.js
similarity index 95%
rename from TaskServer/node_modules/ccxt/js/bitbay.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitbay.js
index f800a571f..f1cb3a288 100644
--- a/TaskServer/node_modules/ccxt/js/bitbay.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitbay.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded, OnMaintenance } = require ('./base/errors');
+const { InvalidNonce, InsufficientFunds, AuthenticationError, InvalidOrder, ExchangeError, OrderNotFound, AccountSuspended, BadSymbol, OrderImmediatelyFillable, RateLimitExceeded, OnMaintenance, PermissionDenied } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -15,11 +15,19 @@ module.exports = class bitbay extends Exchange {
'countries': [ 'MT', 'EU' ], // Malta
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': true,
- 'withdraw': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
- 'fetchOpenOrders': true,
'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '60',
@@ -216,6 +224,11 @@ module.exports = class bitbay extends Exchange {
'OFFER_WOULD_HAVE_BEEN_PARTIALLY_FILLED': OrderImmediatelyFillable,
'ACTION_LIMIT_EXCEEDED': RateLimitExceeded,
'UNDER_MAINTENANCE': OnMaintenance,
+ 'REQUEST_TIMESTAMP_TOO_OLD': InvalidNonce,
+ 'PERMISSIONS_NOT_SUFFICIENT': PermissionDenied,
+ },
+ 'commonCurrencies': {
+ 'GGC': 'Global Game Coin',
},
});
}
@@ -328,22 +341,7 @@ module.exports = class bitbay extends Exchange {
// }
//
const marketId = this.safeString (order, 'market');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.safeInteger (order, 'time');
const amount = this.safeFloat (order, 'startAmount');
const remaining = this.safeFloat (order, 'currentAmount');
@@ -363,8 +361,10 @@ module.exports = class bitbay extends Exchange {
'status': undefined,
'symbol': symbol,
'type': this.safeString (order, 'mode'),
+ 'timeInForce': undefined,
'side': this.safeStringLower (order, 'offerType'),
'price': this.safeFloat (order, 'rate'),
+ 'stopPrice': undefined,
'amount': amount,
'cost': undefined,
'filled': filled,
@@ -827,25 +827,28 @@ module.exports = class bitbay extends Exchange {
return this.safeString (types, type, type);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
- // [
- // '1582399800000',
- // {
- // o: '0.0001428',
- // c: '0.0001428',
- // h: '0.0001428',
- // l: '0.0001428',
- // v: '4',
- // co: '1'
- // }
- // ]
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // '1582399800000',
+ // {
+ // o: '0.0001428',
+ // c: '0.0001428',
+ // h: '0.0001428',
+ // l: '0.0001428',
+ // v: '4',
+ // co: '1'
+ // }
+ // ]
+ //
+ const first = this.safeValue (ohlcv, 1, {});
return [
- parseInt (ohlcv[0]),
- this.safeFloat (ohlcv[1], 'o'),
- this.safeFloat (ohlcv[1], 'h'),
- this.safeFloat (ohlcv[1], 'l'),
- this.safeFloat (ohlcv[1], 'c'),
- this.safeFloat (ohlcv[1], 'v'),
+ this.safeInteger (ohlcv, 0),
+ this.safeFloat (first, 'o'),
+ this.safeFloat (first, 'h'),
+ this.safeFloat (first, 'l'),
+ this.safeFloat (first, 'c'),
+ this.safeFloat (first, 'v'),
];
}
@@ -872,8 +875,18 @@ module.exports = class bitbay extends Exchange {
request['to'] = this.sum (request['from'], timerange);
}
const response = await this.v1_01PublicGetTradingCandleHistorySymbolResolution (this.extend (request, params));
- const ohlcvs = this.safeValue (response, 'items', []);
- return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+ //
+ // {
+ // "status":"Ok",
+ // "items":[
+ // ["1591503060000",{"o":"0.02509572","c":"0.02509438","h":"0.02509664","l":"0.02509438","v":"0.02082165","co":"17"}],
+ // ["1591503120000",{"o":"0.02509606","c":"0.02509515","h":"0.02509606","l":"0.02509487","v":"0.04971703","co":"13"}],
+ // ["1591503180000",{"o":"0.02509532","c":"0.02509589","h":"0.02509589","l":"0.02509454","v":"0.01332236","co":"7"}],
+ // ]
+ // }
+ //
+ const items = this.safeValue (response, 'items', []);
+ return this.parseOHLCVs (items, market, timeframe, since, limit);
}
parseTrade (trade, market = undefined) {
@@ -928,33 +941,11 @@ module.exports = class bitbay extends Exchange {
}
const feeCost = this.safeFloat (trade, 'commissionValue');
const marketId = this.safeString (trade, 'market');
- let base = undefined;
- let quote = undefined;
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- base = market['base'];
- quote = market['quote'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- base = this.safeCurrencyCode (baseId);
- quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (market !== undefined) {
- if (symbol === undefined) {
- symbol = market['symbol'];
- }
- if (base === undefined) {
- base = market['base'];
- }
- }
+ market = this.safeMarket (marketId, market, '-');
+ const symbol = market['symbol'];
let fee = undefined;
if (feeCost !== undefined) {
- const feeCcy = (side === 'buy') ? base : quote;
+ const feeCcy = (side === 'buy') ? market['base'] : market['quote'];
fee = {
'currency': feeCcy,
'cost': feeCost,
@@ -998,7 +989,7 @@ module.exports = class bitbay extends Exchange {
}
const response = await this.v1_01PublicGetTradingTransactionsSymbol (this.extend (request, params));
const items = this.safeValue (response, 'items');
- return this.parseTrades (items, symbol, since, limit);
+ return this.parseTrades (items, market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
@@ -1013,7 +1004,9 @@ module.exports = class bitbay extends Exchange {
};
if (type === 'limit') {
request['rate'] = price;
+ price = parseFloat (price);
}
+ amount = parseFloat (amount);
const response = await this.v1_01PrivatePostTradingOfferSymbol (this.extend (request, params));
//
// unfilled (open order)
@@ -1103,8 +1096,8 @@ module.exports = class bitbay extends Exchange {
'symbol': symbol,
'type': type,
'side': side,
- 'price': parseFloat (price),
- 'amount': parseFloat (amount),
+ 'price': price,
+ 'amount': amount,
'cost': cost,
'filled': filled,
'remaining': remaining,
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitcoincom.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitcoincom.js
new file mode 100644
index 000000000..9321784dc
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitcoincom.js
@@ -0,0 +1,34 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const hitbtc = require ('./hitbtc.js');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class bitcoincom extends hitbtc {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'bitcoincom',
+ 'name': 'bitcoin.com',
+ 'countries': [ 'KN' ],
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/97296144-514fa300-1861-11eb-952b-3d55d492200b.jpg',
+ 'api': {
+ 'public': 'https://api.exchange.bitcoin.com',
+ 'private': 'https://api.exchange.bitcoin.com',
+ },
+ 'www': 'https://exchange.bitcoin.com',
+ 'doc': 'https://api.exchange.bitcoin.com/api/2/explore',
+ 'fees': 'https://exchange.bitcoin.com/fees-and-limits',
+ 'referral': 'https://exchange.bitcoin.com/referral/da948b21d6c92d69',
+ },
+ 'fees': {
+ 'trading': {
+ 'maker': 0.15 / 100,
+ 'taker': 0.2 / 100,
+ },
+ },
+ });
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/bitfinex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitfinex.js
similarity index 91%
rename from TaskServer/node_modules/ccxt/js/bitfinex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitfinex.js
index 95768e94f..ed9038a81 100644
--- a/TaskServer/node_modules/ccxt/js/bitfinex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitfinex.js
@@ -3,8 +3,8 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { NotSupported, RateLimitExceeded, AuthenticationError, PermissionDenied, ArgumentsRequired, ExchangeError, ExchangeNotAvailable, InsufficientFunds, InvalidOrder, OrderNotFound, InvalidNonce } = require ('./base/errors');
-const { SIGNIFICANT_DIGITS } = require ('./base/functions/number');
+const { NotSupported, RateLimitExceeded, AuthenticationError, PermissionDenied, ArgumentsRequired, ExchangeError, ExchangeNotAvailable, InsufficientFunds, InvalidOrder, OrderNotFound, InvalidNonce, BadSymbol } = require ('./base/errors');
+const { SIGNIFICANT_DIGITS, DECIMAL_PLACES, TRUNCATE, ROUND } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -20,22 +20,30 @@ module.exports = class bitfinex extends Exchange {
'pro': true,
// new metainfo interface
'has': {
- 'CORS': false,
'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'CORS': false,
'createDepositAddress': true,
+ 'createOrder': true,
'deposit': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
'fetchDepositAddress': true,
- 'fetchTradingFee': true,
- 'fetchTradingFees': true,
+ 'fetchDeposits': false,
'fetchFundingFees': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTradingFee': true,
+ 'fetchTradingFees': true,
'fetchTransactions': true,
- 'fetchDeposits': false,
'fetchWithdrawals': false,
'withdraw': true,
},
@@ -289,6 +297,10 @@ module.exports = class bitfinex extends Exchange {
'DAT': 'DATA',
'DSH': 'DASH',
'DRK': 'DRK',
+ // https://github.com/ccxt/ccxt/issues/7399
+ // https://coinmarketcap.com/currencies/pnetwork/
+ // https://en.cryptonomist.ch/blog/eidoo/the-edo-to-pnt-upgrade-what-you-need-to-know-updated/
+ 'EDO': 'PNT',
'GSD': 'GUSD',
'HOT': 'Hydro Protocol',
'IOS': 'IOST',
@@ -301,10 +313,12 @@ module.exports = class bitfinex extends Exchange {
'POY': 'POLY',
'QSH': 'QASH',
'QTM': 'QTUM',
+ 'RBT': 'RBTC',
'SEE': 'SEER',
'SNG': 'SNGLS',
'SPK': 'SPANK',
'STJ': 'STORJ',
+ 'TRI': 'TRIO',
'TSD': 'TUSD',
'YYW': 'YOYOW',
'UDC': 'USDC',
@@ -329,8 +343,10 @@ module.exports = class bitfinex extends Exchange {
'Nonce is too small.': InvalidNonce,
'No summary found.': ExchangeError, // fetchTradingFees (summary) endpoint can give this vague error message
'Cannot evaluate your available balance, please try again': ExchangeNotAvailable,
+ 'Unknown symbol': BadSymbol,
},
'broad': {
+ 'Invalid X-BFX-SIGNATURE': AuthenticationError,
'This API key does not have permission': PermissionDenied, // authenticated but not authorized
'not enough exchange balance for ': InsufficientFunds, // when buying cost is greater than the available quote currency
'minimum size for ': InvalidOrder, // when amount below limits.amount.min
@@ -352,9 +368,11 @@ module.exports = class bitfinex extends Exchange {
// 'BCH': 'bcash', // undocumented
'BCI': 'bci',
'BFT': 'bft',
+ 'BSV': 'bsv',
'BTC': 'bitcoin',
'BTG': 'bgold',
'CFI': 'cfi',
+ 'COMP': 'comp',
'DAI': 'dai',
'DADI': 'dad',
'DASH': 'dash',
@@ -373,6 +391,7 @@ module.exports = class bitfinex extends Exchange {
// https://github.com/ccxt/ccxt/issues/5833
'LEO': 'let', // ETH chain
// 'LEO': 'les', // EOS chain
+ 'LINK': 'link',
'LRC': 'lrc',
'LTC': 'litecoin',
'LYM': 'lym',
@@ -398,6 +417,7 @@ module.exports = class bitfinex extends Exchange {
'STORJ': 'stj',
'TNB': 'tnb',
'TRX': 'trx',
+ 'TUSD': 'tsd',
'USD': 'wire',
'USDC': 'udc', // https://github.com/ccxt/ccxt/issues/5833
'UTK': 'utk',
@@ -500,8 +520,11 @@ module.exports = class bitfinex extends Exchange {
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
const precision = {
- 'price': market['price_precision'],
- 'amount': undefined,
+ 'price': this.safeInteger (market, 'price_precision'),
+ // https://docs.bitfinex.com/docs/introduction#amount-precision
+ // The amount field allows up to 8 decimals.
+ // Anything exceeding this will be rounded to the 8th decimal.
+ 'amount': 8,
};
const limits = {
'amount': {
@@ -534,7 +557,19 @@ module.exports = class bitfinex extends Exchange {
}
amountToPrecision (symbol, amount) {
- return this.numberToString (amount);
+ // https://docs.bitfinex.com/docs/introduction#amount-precision
+ // The amount field allows up to 8 decimals.
+ // Anything exceeding this will be rounded to the 8th decimal.
+ return this.decimalToPrecision (amount, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES);
+ }
+
+ priceToPrecision (symbol, price) {
+ price = this.decimalToPrecision (price, ROUND, this.markets[symbol]['precision']['price'], this.precisionMode);
+ // https://docs.bitfinex.com/docs/introduction#price-precision
+ // The precision level of all trading prices is based on significant figures.
+ // All pairs on Bitfinex use up to 5 significant digits and up to 8 decimals (e.g. 1.2345, 123.45, 1234.5, 0.00012345).
+ // Prices submit with a precision larger than 5 will be cut by the API.
+ return this.decimalToPrecision (price, TRUNCATE, 8, DECIMAL_PLACES);
}
calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) {
@@ -612,7 +647,7 @@ module.exports = class bitfinex extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -774,7 +809,7 @@ module.exports = class bitfinex extends Exchange {
async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
await this.loadMarkets ();
const order = {
- 'order_id': id,
+ 'order_id': parseInt (id),
};
if (price !== undefined) {
order['price'] = this.priceToPrecision (symbol, price);
@@ -851,8 +886,10 @@ module.exports = class bitfinex extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': orderType,
+ 'timeInForce': undefined,
'side': side,
'price': this.safeFloat (order, 'price'),
+ 'stopPrice': undefined,
'average': this.safeFloat (order, 'avg_execution_price'),
'amount': this.safeFloat (order, 'original_amount'),
'remaining': this.safeFloat (order, 'remaining_amount'),
@@ -903,7 +940,17 @@ module.exports = class bitfinex extends Exchange {
return this.parseOrder (response);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1457539800000,
+ // 0.02594,
+ // 0.02594,
+ // 0.02594,
+ // 0.02594,
+ // 0.1
+ // ]
+ //
return [
this.safeInteger (ohlcv, 0),
this.safeFloat (ohlcv, 1),
@@ -931,6 +978,13 @@ module.exports = class bitfinex extends Exchange {
request['start'] = since;
}
const response = await this.v2GetCandlesTradeTimeframeSymbolHist (this.extend (request, params));
+ //
+ // [
+ // [1457539800000,0.02594,0.02594,0.02594,0.02594,0.1],
+ // [1457547300000,0.02577,0.02577,0.02577,0.02577,0.01],
+ // [1457550240000,0.0255,0.0253,0.0255,0.0252,3.2640000000000002],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -977,18 +1031,23 @@ module.exports = class bitfinex extends Exchange {
}
async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
- if (code === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchTransactions() requires a currency `code` argument');
- }
await this.loadMarkets ();
- const currency = this.currency (code);
- const request = {
- 'currency': currency['id'],
- };
- if (since !== undefined) {
- request['since'] = parseInt (since / 1000);
+ let currencyId = this.safeString (params, 'currency');
+ const query = this.omit (params, 'currency');
+ let currency = undefined;
+ if (currencyId === undefined) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchTransactions() requires a currency `code` argument or a `currency` parameter');
+ } else {
+ currency = this.currency (code);
+ currencyId = currency['id'];
+ }
}
- const response = await this.privatePostHistoryMovements (this.extend (request, params));
+ query['currency'] = currencyId;
+ if (since !== undefined) {
+ query['since'] = parseInt (since / 1000);
+ }
+ const response = await this.privatePostHistoryMovements (this.extend (query, params));
//
// [
// {
@@ -1125,6 +1184,27 @@ module.exports = class bitfinex extends Exchange {
};
}
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privatePostPositions (params);
+ //
+ // [
+ // {
+ // "id":943715,
+ // "symbol":"btcusd",
+ // "status":"ACTIVE",
+ // "base":"246.94",
+ // "amount":"1.0",
+ // "timestamp":"1444141857.0",
+ // "swap":"0.0",
+ // "pl":"-2.22042"
+ // }
+ // ]
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
nonce () {
return this.milliseconds ();
}
@@ -1153,14 +1233,14 @@ module.exports = class bitfinex extends Exchange {
'request': request,
}, query);
body = this.json (query);
- query = this.encode (body);
- const payload = this.stringToBase64 (query);
+ const payload = this.stringToBase64 (body);
const secret = this.encode (this.secret);
const signature = this.hmac (payload, secret, 'sha384');
headers = {
'X-BFX-APIKEY': this.apiKey,
'X-BFX-PAYLOAD': this.decode (payload),
'X-BFX-SIGNATURE': signature,
+ 'Content-Type': 'application/json',
};
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
diff --git a/TaskServer/node_modules/ccxt/js/bitfinex2.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitfinex2.js
similarity index 75%
rename from TaskServer/node_modules/ccxt/js/bitfinex2.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitfinex2.js
index 86d97b188..5c44875e0 100644
--- a/TaskServer/node_modules/ccxt/js/bitfinex2.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitfinex2.js
@@ -20,28 +20,30 @@ module.exports = class bitfinex2 extends bitfinex {
'has': {
'CORS': false,
'cancelAllOrders': true,
+ 'cancelOrder': true,
'createDepositAddress': true,
'createLimitOrder': true,
'createMarketOrder': true,
'createOrder': true,
- 'cancelOrder': true,
'deposit': false,
'editOrder': false,
- 'fetchDepositAddress': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrder': true,
'fetchClosedOrders': false,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
'fetchFundingFees': false,
'fetchMyTrades': true,
'fetchOHLCV': true,
+ 'fetchOpenOrder': true,
'fetchOpenOrders': true,
'fetchOrder': false,
- 'fetchOpenOrder': true,
- 'fetchClosedOrder': true,
'fetchOrderTrades': true,
'fetchStatus': true,
'fetchTickers': true,
'fetchTradingFee': false,
'fetchTradingFees': false,
- 'fetchTransactions': false,
+ 'fetchTransactions': true,
'withdraw': true,
},
'timeframes': {
@@ -94,12 +96,14 @@ module.exports = class bitfinex2 extends bitfinex {
'conf/pub:map:currency:undl', // maps derivatives symbols to their underlying currency
'conf/pub:map:currency:pool', // maps symbols to underlying network/protocol they operate on
'conf/pub:map:currency:explorer', // maps symbols to their recognised block explorer URLs
+ 'conf/pub:map:currency:tx:fee', // maps currencies to their withdrawal fees https://github.com/ccxt/ccxt/issues/7745
'conf/pub:map:tx:method',
'conf/pub:list:{object}',
'conf/pub:list:{object}:{detail}',
'conf/pub:list:currency',
'conf/pub:list:pair:exchange',
'conf/pub:list:pair:margin',
+ 'conf/pub:list:pair:futures',
'conf/pub:list:competitions',
'conf/pub:info:{object}',
'conf/pub:info:{object}:{detail}',
@@ -323,11 +327,21 @@ module.exports = class bitfinex2 extends bitfinex {
}
async fetchMarkets (params = {}) {
- const response = await this.v1GetSymbolsDetails (params);
+ // todo drop v1 in favor of v2 configs
+ // pub:list:pair:exchange,pub:list:pair:margin,pub:list:pair:futures,pub:info:pair
+ const v2response = await this.publicGetConfPubListPairFutures (params);
+ const v1response = await this.v1GetSymbolsDetails (params);
+ const futuresMarketIds = this.safeValue (v2response, 0, []);
const result = [];
- for (let i = 0; i < response.length; i++) {
- const market = response[i];
+ for (let i = 0; i < v1response.length; i++) {
+ const market = v1response[i];
let id = this.safeStringUpper (market, 'pair');
+ let spot = true;
+ if (this.inArray (id, futuresMarketIds)) {
+ spot = false;
+ }
+ const futures = !spot;
+ const type = spot ? 'spot' : 'futures';
let baseId = undefined;
let quoteId = undefined;
if (id.indexOf (':') >= 0) {
@@ -346,7 +360,7 @@ module.exports = class bitfinex2 extends bitfinex {
quoteId = this.getCurrencyId (quoteId);
const precision = {
'price': this.safeInteger (market, 'price_precision'),
- 'amount': this.safeInteger (market, 'price_precision'),
+ 'amount': 8, // https://github.com/ccxt/ccxt/issues/7310
};
const limits = {
'amount': {
@@ -373,14 +387,164 @@ module.exports = class bitfinex2 extends bitfinex {
'precision': precision,
'limits': limits,
'info': market,
+ 'type': type,
'swap': false,
- 'spot': false,
- 'futures': false,
+ 'spot': spot,
+ 'futures': futures,
});
}
return result;
}
+ async fetchCurrencies (params = {}) {
+ const labels = [
+ 'pub:list:currency',
+ 'pub:map:currency:sym', // maps symbols to their API symbols, BAB > BCH
+ 'pub:map:currency:label', // verbose friendly names, BNT > Bancor
+ 'pub:map:currency:unit', // maps symbols to unit of measure where applicable
+ 'pub:map:currency:undl', // maps derivatives symbols to their underlying currency
+ 'pub:map:currency:pool', // maps symbols to underlying network/protocol they operate on
+ 'pub:map:currency:explorer', // maps symbols to their recognised block explorer URLs
+ 'pub:map:currency:tx:fee', // maps currencies to their withdrawal fees https://github.com/ccxt/ccxt/issues/7745
+ ];
+ const config = labels.join (',');
+ const request = {
+ 'config': config,
+ };
+ const response = await this.publicGetConfConfig (this.extend (request, params));
+ //
+ // [
+ //
+ // a list of symbols
+ // ["AAA","ABS","ADA"],
+ //
+ // // sym
+ // // maps symbols to their API symbols, BAB > BCH
+ // [
+ // [ 'BAB', 'BCH' ],
+ // [ 'CNHT', 'CNHt' ],
+ // [ 'DSH', 'DASH' ],
+ // [ 'IOT', 'IOTA' ],
+ // [ 'LES', 'LEO-EOS' ],
+ // [ 'LET', 'LEO-ERC20' ],
+ // [ 'STJ', 'STORJ' ],
+ // [ 'TSD', 'TUSD' ],
+ // [ 'UDC', 'USDC' ],
+ // [ 'USK', 'USDK' ],
+ // [ 'UST', 'USDt' ],
+ // [ 'USTF0', 'USDt0' ],
+ // [ 'XCH', 'XCHF' ],
+ // [ 'YYW', 'YOYOW' ],
+ // // ...
+ // ],
+ // // label
+ // // verbose friendly names, BNT > Bancor
+ // [
+ // [ 'BAB', 'Bitcoin Cash' ],
+ // [ 'BCH', 'Bitcoin Cash' ],
+ // [ 'LEO', 'Unus Sed LEO' ],
+ // [ 'LES', 'Unus Sed LEO (EOS)' ],
+ // [ 'LET', 'Unus Sed LEO (ERC20)' ],
+ // // ...
+ // ],
+ // // unit
+ // // maps symbols to unit of measure where applicable
+ // [
+ // [ 'IOT', 'Mi|MegaIOTA' ],
+ // ],
+ // // undl
+ // // maps derivatives symbols to their underlying currency
+ // [
+ // [ 'USTF0', 'UST' ],
+ // [ 'BTCF0', 'BTC' ],
+ // [ 'ETHF0', 'ETH' ],
+ // ],
+ // // pool
+ // // maps symbols to underlying network/protocol they operate on
+ // [
+ // [ 'SAN', 'ETH' ], [ 'OMG', 'ETH' ], [ 'AVT', 'ETH' ], [ 'EDO', 'ETH' ],
+ // [ 'ESS', 'ETH' ], [ 'ATD', 'EOS' ], [ 'ADD', 'EOS' ], [ 'MTO', 'EOS' ],
+ // [ 'PNK', 'ETH' ], [ 'BAB', 'BCH' ], [ 'WLO', 'XLM' ], [ 'VLD', 'ETH' ],
+ // [ 'BTT', 'TRX' ], [ 'IMP', 'ETH' ], [ 'SCR', 'ETH' ], [ 'GNO', 'ETH' ],
+ // // ...
+ // ],
+ // // explorer
+ // // maps symbols to their recognised block explorer URLs
+ // [
+ // [
+ // 'AIO',
+ // [
+ // "https://mainnet.aion.network",
+ // "https://mainnet.aion.network/#/account/VAL",
+ // "https://mainnet.aion.network/#/transaction/VAL"
+ // ]
+ // ],
+ // // ...
+ // ],
+ // // fee
+ // // maps currencies to their withdrawal fees
+ // [
+ // ["AAA",[0,0]],
+ // ["ABS",[0,131.3]],
+ // ["ADA",[0,0.3]],
+ // ],
+ // ]
+ //
+ const indexed = {
+ 'sym': this.indexBy (this.safeValue (response, 1, []), 0),
+ 'label': this.indexBy (this.safeValue (response, 2, []), 0),
+ 'unit': this.indexBy (this.safeValue (response, 3, []), 0),
+ 'undl': this.indexBy (this.safeValue (response, 4, []), 0),
+ 'pool': this.indexBy (this.safeValue (response, 5, []), 0),
+ 'explorer': this.indexBy (this.safeValue (response, 6, []), 0),
+ 'fees': this.indexBy (this.safeValue (response, 7, []), 0),
+ };
+ const ids = this.safeValue (response, 0, []);
+ const result = {};
+ for (let i = 0; i < ids.length; i++) {
+ let id = ids[i];
+ const code = this.safeCurrencyCode (id);
+ const label = this.safeValue (indexed['label'], id, []);
+ const name = this.safeString (label, 1);
+ const pool = this.safeValue (indexed['pool'], id, []);
+ const type = this.safeString (pool, 1);
+ const feeValues = this.safeValue (indexed['fees'], id, []);
+ const fees = this.safeValue (feeValues, 1, []);
+ const fee = this.safeFloat (fees, 1);
+ const precision = 8; // default precision, todo: fix "magic constants"
+ id = 'f' + id;
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': [ id, label, pool, feeValues ],
+ 'type': type,
+ 'name': name,
+ 'active': true,
+ 'fee': fee,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': 1 / Math.pow (10, precision),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': 1 / Math.pow (10, precision),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': fee,
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ return result;
+ }
+
async fetchBalance (params = {}) {
// this api call does not return the 'used' amount - use the v1 version instead (which also returns zero balances)
await this.loadMarkets ();
@@ -504,7 +668,7 @@ module.exports = class bitfinex2 extends bitfinex {
result[symbol] = this.parseTicker (ticker, market);
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -690,22 +854,32 @@ module.exports = class bitfinex2 extends bitfinex {
'limit': limit,
};
const response = await this.publicGetCandlesTradeTimeframeSymbolHist (this.extend (request, params));
+ //
+ // [
+ // [1591503840000,0.025069,0.025068,0.025069,0.025068,1.97828998],
+ // [1591504500000,0.025065,0.025065,0.025065,0.025065,1.0164],
+ // [1591504620000,0.025062,0.025062,0.025062,0.025062,0.5],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
parseOrderStatus (status) {
+ if (status === undefined) {
+ return status;
+ }
+ const parts = status.split (' ');
+ const state = this.safeString (parts, 0);
const statuses = {
'ACTIVE': 'open',
- 'PARTIALLY FILLED': 'open',
+ 'PARTIALLY': 'open',
'EXECUTED': 'closed',
'CANCELED': 'canceled',
- 'CANCELED was: PARTIALLY FILLED': 'canceled',
- 'INSUFFICIENT MARGIN': 'canceled',
- 'INSUFFICIENT BALANCE (G1) was: PARTIALLY FILLED': 'canceled',
+ 'INSUFFICIENT': 'canceled',
'RSN_DUST': 'rejected',
'RSN_PAUSE': 'rejected',
};
- return this.safeString (statuses, status, status);
+ return this.safeString (statuses, state, status);
}
parseOrder (order, market = undefined) {
@@ -748,8 +922,10 @@ module.exports = class bitfinex2 extends bitfinex {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': average,
@@ -775,6 +951,11 @@ module.exports = class bitfinex2 extends bitfinex {
if (type !== 'market') {
request['price'] = this.numberToString (price);
}
+ const clientOrderId = this.safeValue2 (params, 'cid', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['cid'] = clientOrderId;
+ params = this.omit (params, [ 'cid', 'clientOrderId' ]);
+ }
const response = await this.privatePostAuthWOrderSubmit (this.extend (request, params));
//
// [
@@ -844,17 +1025,18 @@ module.exports = class bitfinex2 extends bitfinex {
}
async cancelOrder (id, symbol = undefined, params = {}) {
- const cid = this.safeValue (params, 'cid'); // client order id
+ const cid = this.safeValue2 (params, 'cid', 'clientOrderId'); // client order id
let request = undefined;
if (cid !== undefined) {
const cidDate = this.safeValue (params, 'cidDate'); // client order id date
if (cidDate === undefined) {
- throw new InvalidOrder (this.id + " canceling an order by client order id ('cid') requires both 'cid' and 'cid_date' ('YYYY-MM-DD')");
+ throw new InvalidOrder (this.id + " canceling an order by clientOrderId ('cid') requires both 'cid' and 'cid_date' ('YYYY-MM-DD')");
}
request = {
'cid': cid,
'cid_date': cidDate,
};
+ params = this.omit (params, [ 'cid', 'clientOrderId' ]);
} else {
request = {
'id': parseInt (id),
@@ -1015,6 +1197,16 @@ module.exports = class bitfinex2 extends bitfinex {
};
}
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'SUCCESS': 'ok',
+ 'ERROR': 'failed',
+ 'FAILURE': 'failed',
+ 'CANCELED': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
parseTransaction (transaction, currency = undefined) {
//
// withdraw
@@ -1040,38 +1232,101 @@ module.exports = class bitfinex2 extends bitfinex {
// "Invalid bitcoin address (abcdef)", // TEXT Text of the notification
// ]
//
- // todo add support for all movements, deposits and withdrawals
+ // fetchTransactions
//
- const data = this.safeValue (transaction, 4, []);
- const timestamp = this.safeInteger (transaction, 0);
+ // [
+ // 13293039, // ID
+ // 'ETH', // CURRENCY
+ // 'ETHEREUM', // CURRENCY_NAME
+ // null,
+ // null,
+ // 1574175052000, // MTS_STARTED
+ // 1574181326000, // MTS_UPDATED
+ // null,
+ // null,
+ // 'CANCELED', // STATUS
+ // null,
+ // null,
+ // -0.24, // AMOUNT, negative for withdrawals
+ // -0.00135, // FEES
+ // null,
+ // null,
+ // 'DESTINATION_ADDRESS',
+ // null,
+ // null,
+ // null,
+ // 'TRANSACTION_ID',
+ // "Purchase of 100 pizzas", // WITHDRAW_TRANSACTION_NOTE
+ // ]
+ //
+ const transactionLength = transaction.length;
+ let timestamp = undefined;
+ let updated = undefined;
let code = undefined;
- if (currency !== undefined) {
- code = currency['code'];
- }
- let feeCost = this.safeFloat (data, 8);
- if (feeCost !== undefined) {
- feeCost = Math.abs (feeCost);
- }
- const amount = this.safeFloat (data, 5);
- let id = this.safeValue (data, 0);
- let status = 'ok';
- if (id === 0) {
- id = undefined;
- status = 'failed';
+ let amount = undefined;
+ let id = undefined;
+ let status = undefined;
+ let tag = undefined;
+ let type = undefined;
+ let feeCost = undefined;
+ let txid = undefined;
+ let addressTo = undefined;
+ if (transactionLength < 9) {
+ const data = this.safeValue (transaction, 4, []);
+ timestamp = this.safeInteger (transaction, 0);
+ if (currency !== undefined) {
+ code = currency['code'];
+ }
+ feeCost = this.safeFloat (data, 8);
+ if (feeCost !== undefined) {
+ feeCost = -feeCost;
+ }
+ amount = this.safeFloat (data, 5);
+ id = this.safeValue (data, 0);
+ status = 'ok';
+ if (id === 0) {
+ id = undefined;
+ status = 'failed';
+ }
+ tag = this.safeString (data, 3);
+ type = 'withdrawal';
+ } else {
+ id = this.safeString (transaction, 0);
+ timestamp = this.safeInteger (transaction, 5);
+ updated = this.safeInteger (transaction, 6);
+ status = this.parseTransactionStatus (this.safeString (transaction, 9));
+ amount = this.safeFloat (transaction, 12);
+ if (amount !== undefined) {
+ if (amount < 0) {
+ type = 'withdrawal';
+ } else {
+ type = 'deposit';
+ }
+ }
+ feeCost = this.safeFloat (transaction, 13);
+ if (feeCost !== undefined) {
+ feeCost = -feeCost;
+ }
+ addressTo = this.safeString (transaction, 16);
+ txid = this.safeString (transaction, 20);
}
return {
'info': transaction,
'id': id,
- 'txid': undefined,
+ 'txid': txid,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'address': undefined, // this is actually the tag for XRP transfers (the address is missing)
- 'tag': this.safeString (data, 3), // refix it properly for the tag from description
- 'type': 'withdrawal',
+ 'addressFrom': undefined,
+ 'address': addressTo, // this is actually the tag for XRP transfers (the address is missing)
+ 'addressTo': addressTo,
+ 'tagFrom': undefined,
+ 'tag': tag, // refix it properly for the tag from description
+ 'tagTo': tag,
+ 'type': type,
'amount': amount,
'currency': code,
'status': status,
- 'updated': undefined,
+ 'updated': updated,
'fee': {
'currency': code,
'cost': feeCost,
@@ -1080,6 +1335,54 @@ module.exports = class bitfinex2 extends bitfinex {
};
}
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let currency = undefined;
+ const request = {};
+ let method = 'privatePostAuthRMovementsHist';
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency'] = currency['id'];
+ method = 'privatePostAuthRMovementsCurrencyHist';
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // max 1000
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // [
+ // [
+ // 13293039, // ID
+ // 'ETH', // CURRENCY
+ // 'ETHEREUM', // CURRENCY_NAME
+ // null,
+ // null,
+ // 1574175052000, // MTS_STARTED
+ // 1574181326000, // MTS_UPDATED
+ // null,
+ // null,
+ // 'CANCELED', // STATUS
+ // null,
+ // null,
+ // -0.24, // AMOUNT, negative for withdrawals
+ // -0.00135, // FEES
+ // null,
+ // null,
+ // 'DESTINATION_ADDRESS',
+ // null,
+ // null,
+ // null,
+ // 'TRANSACTION_ID',
+ // "Purchase of 100 pizzas", // WITHDRAW_TRANSACTION_NOTE
+ // ]
+ // ]
+ //
+ return this.parseTransactions (response, currency, since, limit);
+ }
+
async withdraw (code, amount, address, tag = undefined, params = {}) {
this.checkAddress (address);
await this.loadMarkets ();
@@ -1128,6 +1431,47 @@ module.exports = class bitfinex2 extends bitfinex {
});
}
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privatePostPositions (params);
+ //
+ // [
+ // [
+ // "tBTCUSD", // SYMBOL
+ // "ACTIVE", // STATUS
+ // 0.0195, // AMOUNT
+ // 8565.0267019, // BASE_PRICE
+ // 0, // MARGIN_FUNDING
+ // 0, // MARGIN_FUNDING_TYPE
+ // -0.33455568705000516, // PL
+ // -0.0003117550117425625, // PL_PERC
+ // 7045.876419249083, // PRICE_LIQ
+ // 3.0673001895895604, // LEVERAGE
+ // null, // _PLACEHOLDER
+ // 142355652, // POSITION_ID
+ // 1574002216000, // MTS_CREATE
+ // 1574002216000, // MTS_UPDATE
+ // null, // _PLACEHOLDER
+ // 0, // TYPE
+ // null, // _PLACEHOLDER
+ // 0, // COLLATERAL
+ // 0, // COLLATERAL_MIN
+ // // META
+ // {
+ // "reason":"TRADE",
+ // "order_id":34271018124,
+ // "liq_stage":null,
+ // "trade_price":"8565.0267019",
+ // "trade_amount":"0.0195",
+ // "order_id_oppo":34277498022
+ // }
+ // ]
+ // ]
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
nonce () {
return this.milliseconds ();
}
diff --git a/TaskServer/node_modules/ccxt/js/bitflyer.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitflyer.js
similarity index 90%
rename from TaskServer/node_modules/ccxt/js/bitflyer.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitflyer.js
index a9c5e99dc..99c60448b 100644
--- a/TaskServer/node_modules/ccxt/js/bitflyer.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitflyer.js
@@ -15,19 +15,27 @@ module.exports = class bitflyer extends Exchange {
'countries': [ 'JP' ],
'version': 'v1',
'rateLimit': 1000, // their nonce-timestamp is in seconds...
+ 'hostname': 'bitflyer.com', // or bitflyer.com
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'withdraw': true,
- 'fetchMyTrades': true,
- 'fetchOrders': true,
- 'fetchOrder': 'emulated',
- 'fetchOpenOrders': 'emulated',
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': 'emulated',
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': 'emulated',
+ 'fetchOrder': 'emulated',
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/28051642-56154182-660e-11e7-9b0d-6042d1e6edd8.jpg',
- 'api': 'https://api.bitflyer.jp',
- 'www': 'https://bitflyer.jp',
+ 'api': 'https://api.{hostname}',
+ 'www': 'https://bitflyer.com',
'doc': 'https://lightning.bitflyer.com/docs?lang=en',
},
'api': {
@@ -334,16 +342,8 @@ module.exports = class bitflyer extends Exchange {
const status = this.parseOrderStatus (this.safeString (order, 'child_order_state'));
const type = this.safeStringLower (order, 'child_order_type');
const side = this.safeStringLower (order, 'side');
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'product_code');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'product_code');
+ const symbol = this.safeSymbol (marketId, market);
let fee = undefined;
const feeCost = this.safeFloat (order, 'total_commission');
if (feeCost !== undefined) {
@@ -364,8 +364,10 @@ module.exports = class bitflyer extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -436,6 +438,36 @@ module.exports = class bitflyer extends Exchange {
return this.parseTrades (response, market, since, limit);
}
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbols === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchPositions requires a `symbols` argument, exactly one symbol in an array');
+ }
+ await this.loadMarkets ();
+ const request = {
+ 'product_code': this.marketIds (symbols),
+ };
+ const response = await this.privateGetpositions (this.extend (request, params));
+ //
+ // [
+ // {
+ // "product_code": "FX_BTC_JPY",
+ // "side": "BUY",
+ // "price": 36000,
+ // "size": 10,
+ // "commission": 0,
+ // "swap_point_accumulate": -35,
+ // "require_collateral": 120000,
+ // "open_date": "2015-11-03T10:04:45.011",
+ // "leverage": 3,
+ // "pnl": 965,
+ // "sfd": -0.5
+ // }
+ // ]
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
async withdraw (code, amount, address, tag = undefined, params = {}) {
this.checkAddress (address);
await this.loadMarkets ();
@@ -467,7 +499,8 @@ module.exports = class bitflyer extends Exchange {
request += '?' + this.urlencode (params);
}
}
- const url = this.urls['api'] + request;
+ const baseUrl = this.implodeParams (this.urls['api'], { 'hostname': this.hostname });
+ const url = baseUrl + request;
if (api === 'private') {
this.checkRequiredCredentials ();
const nonce = this.nonce ().toString ();
diff --git a/TaskServer/node_modules/ccxt/js/bitforex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitforex.js
similarity index 93%
rename from TaskServer/node_modules/ccxt/js/bitforex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitforex.js
index 4cb110431..9932a4d34 100644
--- a/TaskServer/node_modules/ccxt/js/bitforex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitforex.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, AuthenticationError, OrderNotFound, InsufficientFunds, DDoSProtection } = require ('./base/errors');
+const { ExchangeError, AuthenticationError, OrderNotFound, InsufficientFunds, DDoSProtection, PermissionDenied } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -15,19 +15,20 @@ module.exports = class bitforex extends Exchange {
'countries': [ 'CN' ],
'version': 'v1',
'has': {
- 'fetchBalance': true,
- 'fetchMarkets': true,
- 'createOrder': true,
'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': false,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
'fetchTicker': true,
'fetchTickers': false,
- 'fetchMyTrades': false,
'fetchTrades': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'fetchOHLCV': true,
},
'timeframes': {
'1m': '1min',
@@ -43,7 +44,7 @@ module.exports = class bitforex extends Exchange {
'1M': '1month',
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/44310033-69e9e600-a3d8-11e8-873d-54d74d1bc4e4.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295553-1160ec00-c50e-11ea-8ea0-df79276a9646.jpg',
'api': 'https://api.bitforex.com',
'www': 'https://www.bitforex.com',
'doc': 'https://github.com/githubdev2020/API_Doc_en/wiki',
@@ -221,12 +222,15 @@ module.exports = class bitforex extends Exchange {
},
},
'commonCurrencies': {
+ 'CREDIT': 'TerraCredit',
+ 'IQ': 'IQ.Cash',
'UOS': 'UOS Network',
},
'exceptions': {
'4004': OrderNotFound,
'1013': AuthenticationError,
'1016': AuthenticationError,
+ '1017': PermissionDenied, // {"code":"1017","success":false,"time":1602670594367,"message":"IP not allow"}
'3002': InsufficientFunds,
'10204': DDoSProtection,
},
@@ -380,7 +384,18 @@ module.exports = class bitforex extends Exchange {
};
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "close":0.02505143,
+ // "currencyVol":0,
+ // "high":0.02506422,
+ // "low":0.02505143,
+ // "open":0.02506095,
+ // "time":1591508940000,
+ // "vol":51.1869
+ // }
+ //
return [
this.safeInteger (ohlcv, 'time'),
this.safeFloat (ohlcv, 'open'),
@@ -402,8 +417,19 @@ module.exports = class bitforex extends Exchange {
request['size'] = limit; // default 1, max 600
}
const response = await this.publicGetApiV1MarketKline (this.extend (request, params));
- const ohlcvs = this.safeValue (response, 'data', []);
- return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
+ //
+ // {
+ // "data":[
+ // {"close":0.02505143,"currencyVol":0,"high":0.02506422,"low":0.02505143,"open":0.02506095,"time":1591508940000,"vol":51.1869},
+ // {"close":0.02503914,"currencyVol":0,"high":0.02506687,"low":0.02503914,"open":0.02505358,"time":1591509000000,"vol":9.1082},
+ // {"close":0.02505172,"currencyVol":0,"high":0.02507466,"low":0.02503895,"open":0.02506371,"time":1591509060000,"vol":63.7431},
+ // ],
+ // "success":true,
+ // "time":1591509427131
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -472,8 +498,10 @@ module.exports = class bitforex extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitget.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitget.js
new file mode 100644
index 000000000..78e7fe8aa
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitget.js
@@ -0,0 +1,2904 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, ExchangeNotAvailable, OnMaintenance, ArgumentsRequired, BadRequest, AccountSuspended, InvalidAddress, PermissionDenied, DDoSProtection, InsufficientFunds, InvalidNonce, CancelPending, InvalidOrder, OrderNotFound, AuthenticationError, RequestTimeout, NotSupported, BadSymbol, RateLimitExceeded } = require ('./base/errors');
+const { TICK_SIZE } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class bitget extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'bitget',
+ 'name': 'Bitget',
+ 'countries': [ 'SG' ],
+ 'version': 'v3',
+ 'rateLimit': 1000, // up to 3000 requests per 5 minutes ≈ 600 requests per minute ≈ 10 requests per second ≈ 100 ms
+ 'has': {
+ 'cancelOrder': true,
+ 'cancelOrders': true,
+ 'CORS': false,
+ 'createOrder': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOpenOrders': true,
+ 'fetchClosedOrders': true,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '5m': '5m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '2h': '2h',
+ '4h': '4h',
+ '6h': '6h',
+ '12h': '12h',
+ '1d': '1d',
+ '1w': '1w',
+ },
+ 'hostname': 'bitget.com',
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/51840849/88317935-a8a21c80-cd22-11ea-8e2b-4b9fac5975eb.jpg',
+ 'api': {
+ 'data': 'https://api.{hostname}',
+ 'api': 'https://api.{hostname}',
+ 'capi': 'https://capi.{hostname}',
+ 'swap': 'https://capi.{hostname}',
+ },
+ 'www': 'https://www.bitget.com',
+ 'doc': [
+ 'https://bitgetlimited.github.io/apidoc/en/swap',
+ 'https://bitgetlimited.github.io/apidoc/en/spot',
+ ],
+ 'fees': 'https://www.bitget.cc/zh-CN/rate?tab=1',
+ 'test': {
+ 'rest': 'https://testnet.bitget.com',
+ },
+ 'referral': 'https://www.bitget.com/expressly?languageType=0&channelCode=ccxt&vipCode=tg9j',
+ },
+ 'api': {
+ 'data': {
+ 'get': [
+ 'market/history/kline', // Kline data
+ 'market/detail/merged', // Get aggregated ticker
+ 'market/tickers', // Get all trading tickers
+ 'market/allticker', // Get all trading market method 2
+ 'market/depth', // Get Market Depth Data
+ 'market/trade', // Get Trade Detail Data
+ 'market/history/trade', // Get record of trading
+ 'market/detail', // Get Market Detail 24h Volume
+ 'common/symbols', // Query all trading pairs and accuracy supported in the station
+ 'common/currencys', // Query all currencies supported in the station
+ 'common/timestamp', // Query system current time
+ ],
+ },
+ 'api': {
+ 'get': [
+ 'account/accounts', // Get all accounts of current user(即account_id)。
+ 'accounts/{account_id}/balance', // Get the balance of the specified account
+ 'order/orders', // Query order, deprecated
+ 'order/orders/openOrders',
+ 'order/orders/history',
+ 'order/deposit_withdraw', // Query assets history
+ ],
+ 'post': [
+ 'order/orders/place', // Place order
+ 'order/orders/{order_id}/submitcancel', // Request to cancel an order request
+ 'order/orders/batchcancel', // Bulk order cancellation
+ 'order/orders/{order_id}', // Query an order details
+ 'order/orders/{order_id}/matchresults', // Query the transaction details of an order
+ 'order/matchresults', // Query current order, order history
+ ],
+ },
+ 'capi': {
+ 'get': [
+ 'market/time',
+ 'market/contracts',
+ 'market/depth',
+ 'market/tickers',
+ 'market/ticker',
+ 'market/trades',
+ 'market/candles',
+ 'market/index',
+ 'market/open_count',
+ 'market/open_interest',
+ 'market/price_limit',
+ 'market/funding_time',
+ 'market/mark_price',
+ 'market/open_count',
+ 'market/historyFundRate',
+ ],
+ },
+ 'swap': {
+ 'get': [
+ 'account/accounts',
+ 'account/account',
+ 'account/settings',
+ 'position/allPosition',
+ 'position/singlePosition',
+ 'position/holds',
+ 'order/detail',
+ 'order/orders',
+ 'order/fills',
+ 'order/current',
+ 'order/currentPlan', // conditional
+ 'order/history',
+ 'order/historyPlan', // conditional
+ 'trace/closeTrack',
+ 'trace/currentTrack',
+ 'trace/historyTrack',
+ ],
+ 'post': [
+ 'account/leverage',
+ 'account/adjustMargin',
+ 'account/modifyAutoAppendMargin',
+ 'order/placeOrder',
+ 'order/batchOrders',
+ 'order/cancel_order',
+ 'order/cancel_batch_orders',
+ 'order/plan_order',
+ 'order/cancel_plan',
+ 'position/changeHoldModel',
+ ],
+ },
+ },
+ 'fees': {
+ 'spot': {
+ 'taker': 0.002,
+ 'maker': 0.002,
+ },
+ 'swap': {
+ 'taker': 0.0006,
+ 'maker': 0.0004,
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ 'password': true,
+ },
+ 'exceptions': {
+ // http error codes
+ // 400 Bad Request — Invalid request format
+ // 401 Unauthorized — Invalid API Key
+ // 403 Forbidden — You do not have access to the requested resource
+ // 404 Not Found
+ // 500 Internal Server Error — We had a problem with our server
+ 'exact': {
+ '1': ExchangeError, // { "code": 1, "message": "System error" }
+ // undocumented
+ 'failure to get a peer from the ring-balancer': ExchangeNotAvailable, // { "message": "failure to get a peer from the ring-balancer" }
+ '4010': PermissionDenied, // { "code": 4010, "message": "For the security of your funds, withdrawals are not permitted within 24 hours after changing fund password / mobile number / Google Authenticator settings " }
+ // common
+ // '0': ExchangeError, // 200 successful,when the order placement / cancellation / operation is successful
+ '4001': ExchangeError, // no data received in 30s
+ '4002': ExchangeError, // Buffer full. cannot write data
+ // --------------------------------------------------------
+ '30001': AuthenticationError, // { "code": 30001, "message": 'request header "OK_ACCESS_KEY" cannot be blank'}
+ '30002': AuthenticationError, // { "code": 30002, "message": 'request header "OK_ACCESS_SIGN" cannot be blank'}
+ '30003': AuthenticationError, // { "code": 30003, "message": 'request header "OK_ACCESS_TIMESTAMP" cannot be blank'}
+ '30004': AuthenticationError, // { "code": 30004, "message": 'request header "OK_ACCESS_PASSPHRASE" cannot be blank'}
+ '30005': InvalidNonce, // { "code": 30005, "message": "invalid OK_ACCESS_TIMESTAMP" }
+ '30006': AuthenticationError, // { "code": 30006, "message": "invalid OK_ACCESS_KEY" }
+ '30007': BadRequest, // { "code": 30007, "message": 'invalid Content_Type, please use "application/json" format'}
+ '30008': RequestTimeout, // { "code": 30008, "message": "timestamp request expired" }
+ '30009': ExchangeError, // { "code": 30009, "message": "system error" }
+ '30010': AuthenticationError, // { "code": 30010, "message": "API validation failed" }
+ '30011': PermissionDenied, // { "code": 30011, "message": "invalid IP" }
+ '30012': AuthenticationError, // { "code": 30012, "message": "invalid authorization" }
+ '30013': AuthenticationError, // { "code": 30013, "message": "invalid sign" }
+ '30014': DDoSProtection, // { "code": 30014, "message": "request too frequent" }
+ '30015': AuthenticationError, // { "code": 30015, "message": 'request header "OK_ACCESS_PASSPHRASE" incorrect'}
+ '30016': ExchangeError, // { "code": 30015, "message": "you are using v1 apiKey, please use v1 endpoint. If you would like to use v3 endpoint, please subscribe to v3 apiKey" }
+ '30017': ExchangeError, // { "code": 30017, "message": "apikey's broker id does not match" }
+ '30018': ExchangeError, // { "code": 30018, "message": "apikey's domain does not match" }
+ '30019': ExchangeNotAvailable, // { "code": 30019, "message": "Api is offline or unavailable" }
+ '30020': BadRequest, // { "code": 30020, "message": "body cannot be blank" }
+ '30021': BadRequest, // { "code": 30021, "message": "Json data format error" }, { "code": 30021, "message": "json data format error" }
+ '30022': PermissionDenied, // { "code": 30022, "message": "Api has been frozen" }
+ '30023': BadRequest, // { "code": 30023, "message": "{0} parameter cannot be blank" }
+ '30024': BadSymbol, // {"code":30024,"message":"\"instrument_id\" is an invalid parameter"}
+ '30025': BadRequest, // { "code": 30025, "message": "{0} parameter category error" }
+ '30026': DDoSProtection, // { "code": 30026, "message": "requested too frequent" }
+ '30027': AuthenticationError, // { "code": 30027, "message": "login failure" }
+ '30028': PermissionDenied, // { "code": 30028, "message": "unauthorized execution" }
+ '30029': AccountSuspended, // { "code": 30029, "message": "account suspended" }
+ '30030': ExchangeError, // { "code": 30030, "message": "endpoint request failed. Please try again" }
+ '30031': BadRequest, // { "code": 30031, "message": "token does not exist" }
+ '30032': BadSymbol, // { "code": 30032, "message": "pair does not exist" }
+ '30033': BadRequest, // { "code": 30033, "message": "exchange domain does not exist" }
+ '30034': ExchangeError, // { "code": 30034, "message": "exchange ID does not exist" }
+ '30035': ExchangeError, // { "code": 30035, "message": "trading is not supported in this website" }
+ '30036': ExchangeError, // { "code": 30036, "message": "no relevant data" }
+ '30037': ExchangeNotAvailable, // { "code": 30037, "message": "endpoint is offline or unavailable" }
+ // '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" }
+ '30038': OnMaintenance, // {"client_oid":"","code":"30038","error_code":"30038","error_message":"Matching engine is being upgraded. Please try in about 1 minute.","message":"Matching engine is being upgraded. Please try in about 1 minute.","order_id":"-1","result":false}
+ // futures
+ '32001': AccountSuspended, // { "code": 32001, "message": "futures account suspended" }
+ '32002': PermissionDenied, // { "code": 32002, "message": "futures account does not exist" }
+ '32003': CancelPending, // { "code": 32003, "message": "canceling, please wait" }
+ '32004': ExchangeError, // { "code": 32004, "message": "you have no unfilled orders" }
+ '32005': InvalidOrder, // { "code": 32005, "message": "max order quantity" }
+ '32006': InvalidOrder, // { "code": 32006, "message": "the order price or trigger price exceeds USD 1 million" }
+ '32007': InvalidOrder, // { "code": 32007, "message": "leverage level must be the same for orders on the same side of the contract" }
+ '32008': InvalidOrder, // { "code": 32008, "message": "Max. positions to open (cross margin)" }
+ '32009': InvalidOrder, // { "code": 32009, "message": "Max. positions to open (fixed margin)" }
+ '32010': ExchangeError, // { "code": 32010, "message": "leverage cannot be changed with open positions" }
+ '32011': ExchangeError, // { "code": 32011, "message": "futures status error" }
+ '32012': ExchangeError, // { "code": 32012, "message": "futures order update error" }
+ '32013': ExchangeError, // { "code": 32013, "message": "token type is blank" }
+ '32014': ExchangeError, // { "code": 32014, "message": "your number of contracts closing is larger than the number of contracts available" }
+ '32015': ExchangeError, // { "code": 32015, "message": "margin ratio is lower than 100% before opening positions" }
+ '32016': ExchangeError, // { "code": 32016, "message": "margin ratio is lower than 100% after opening position" }
+ '32017': ExchangeError, // { "code": 32017, "message": "no BBO" }
+ '32018': ExchangeError, // { "code": 32018, "message": "the order quantity is less than 1, please try again" }
+ '32019': ExchangeError, // { "code": 32019, "message": "the order price deviates from the price of the previous minute by more than 3%" }
+ '32020': ExchangeError, // { "code": 32020, "message": "the price is not in the range of the price limit" }
+ '32021': ExchangeError, // { "code": 32021, "message": "leverage error" }
+ '32022': ExchangeError, // { "code": 32022, "message": "this function is not supported in your country or region according to the regulations" }
+ '32023': ExchangeError, // { "code": 32023, "message": "this account has outstanding loan" }
+ '32024': ExchangeError, // { "code": 32024, "message": "order cannot be placed during delivery" }
+ '32025': ExchangeError, // { "code": 32025, "message": "order cannot be placed during settlement" }
+ '32026': ExchangeError, // { "code": 32026, "message": "your account is restricted from opening positions" }
+ '32027': ExchangeError, // { "code": 32027, "message": "cancelled over 20 orders" }
+ '32028': AccountSuspended, // { "code": 32028, "message": "account is suspended and liquidated" }
+ '32029': ExchangeError, // { "code": 32029, "message": "order info does not exist" }
+ '32030': InvalidOrder, // The order cannot be cancelled
+ '32031': ArgumentsRequired, // client_oid or order_id is required.
+ '32038': AuthenticationError, // User does not exist
+ '32040': ExchangeError, // User have open contract orders or position
+ '32044': ExchangeError, // { "code": 32044, "message": "The margin ratio after submitting this order is lower than the minimum requirement ({0}) for your tier." }
+ '32045': ExchangeError, // String of commission over 1 million
+ '32046': ExchangeError, // Each user can hold up to 10 trade plans at the same time
+ '32047': ExchangeError, // system error
+ '32048': InvalidOrder, // Order strategy track range error
+ '32049': ExchangeError, // Each user can hold up to 10 track plans at the same time
+ '32050': InvalidOrder, // Order strategy rang error
+ '32051': InvalidOrder, // Order strategy ice depth error
+ '32052': ExchangeError, // String of commission over 100 thousand
+ '32053': ExchangeError, // Each user can hold up to 6 ice plans at the same time
+ '32057': ExchangeError, // The order price is zero. Market-close-all function cannot be executed
+ '32054': ExchangeError, // Trade not allow
+ '32055': InvalidOrder, // cancel order error
+ '32056': ExchangeError, // iceberg per order average should between {0}-{1} contracts
+ '32058': ExchangeError, // Each user can hold up to 6 initiative plans at the same time
+ '32059': InvalidOrder, // Total amount should exceed per order amount
+ '32060': InvalidOrder, // Order strategy type error
+ '32061': InvalidOrder, // Order strategy initiative limit error
+ '32062': InvalidOrder, // Order strategy initiative range error
+ '32063': InvalidOrder, // Order strategy initiative rate error
+ '32064': ExchangeError, // Time Stringerval of orders should set between 5-120s
+ '32065': ExchangeError, // Close amount exceeds the limit of Market-close-all (999 for BTC, and 9999 for the rest tokens)
+ '32066': ExchangeError, // You have open orders. Please cancel all open orders before changing your leverage level.
+ '32067': ExchangeError, // Account equity < required margin in this setting. Please adjust your leverage level again.
+ '32068': ExchangeError, // The margin for this position will fall short of the required margin in this setting. Please adjust your leverage level or increase your margin to proceed.
+ '32069': ExchangeError, // Target leverage level too low. Your account balance is insufficient to cover the margin required. Please adjust the leverage level again.
+ '32070': ExchangeError, // Please check open position or unfilled order
+ '32071': ExchangeError, // Your current liquidation mode does not support this action.
+ '32072': ExchangeError, // The highest available margin for your order’s tier is {0}. Please edit your margin and place a new order.
+ '32073': ExchangeError, // The action does not apply to the token
+ '32074': ExchangeError, // The number of contracts of your position, open orders, and the current order has exceeded the maximum order limit of this asset.
+ '32075': ExchangeError, // Account risk rate breach
+ '32076': ExchangeError, // Liquidation of the holding position(s) at market price will require cancellation of all pending close orders of the contracts.
+ '32077': ExchangeError, // Your margin for this asset in futures account is insufficient and the position has been taken over for liquidation. (You will not be able to place orders, close positions, transfer funds, or add margin during this period of time. Your account will be restored after the liquidation is complete.)
+ '32078': ExchangeError, // Please cancel all open orders before switching the liquidation mode(Please cancel all open orders before switching the liquidation mode)
+ '32079': ExchangeError, // Your open positions are at high risk.(Please add margin or reduce positions before switching the mode)
+ '32080': ExchangeError, // Funds cannot be transferred out within 30 minutes after futures settlement
+ '32083': ExchangeError, // The number of contracts should be a positive multiple of %%. Please place your order again
+ // token and margin trading
+ '33001': PermissionDenied, // { "code": 33001, "message": "margin account for this pair is not enabled yet" }
+ '33002': AccountSuspended, // { "code": 33002, "message": "margin account for this pair is suspended" }
+ '33003': InsufficientFunds, // { "code": 33003, "message": "no loan balance" }
+ '33004': ExchangeError, // { "code": 33004, "message": "loan amount cannot be smaller than the minimum limit" }
+ '33005': ExchangeError, // { "code": 33005, "message": "repayment amount must exceed 0" }
+ '33006': ExchangeError, // { "code": 33006, "message": "loan order not found" }
+ '33007': ExchangeError, // { "code": 33007, "message": "status not found" }
+ '33008': InsufficientFunds, // { "code": 33008, "message": "loan amount cannot exceed the maximum limit" }
+ '33009': ExchangeError, // { "code": 33009, "message": "user ID is blank" }
+ '33010': ExchangeError, // { "code": 33010, "message": "you cannot cancel an order during session 2 of call auction" }
+ '33011': ExchangeError, // { "code": 33011, "message": "no new market data" }
+ '33012': ExchangeError, // { "code": 33012, "message": "order cancellation failed" }
+ '33013': InvalidOrder, // { "code": 33013, "message": "order placement failed" }
+ '33014': OrderNotFound, // { "code": 33014, "message": "order does not exist" }
+ '33015': InvalidOrder, // { "code": 33015, "message": "exceeded maximum limit" }
+ '33016': ExchangeError, // { "code": 33016, "message": "margin trading is not open for this token" }
+ '33017': InsufficientFunds, // { "code": 33017, "message": "insufficient balance" }
+ '33018': ExchangeError, // { "code": 33018, "message": "this parameter must be smaller than 1" }
+ '33020': ExchangeError, // { "code": 33020, "message": "request not supported" }
+ '33021': BadRequest, // { "code": 33021, "message": "token and the pair do not match" }
+ '33022': InvalidOrder, // { "code": 33022, "message": "pair and the order do not match" }
+ '33023': ExchangeError, // { "code": 33023, "message": "you can only place market orders during call auction" }
+ '33024': InvalidOrder, // { "code": 33024, "message": "trading amount too small" }
+ '33025': InvalidOrder, // { "code": 33025, "message": "base token amount is blank" }
+ '33026': ExchangeError, // { "code": 33026, "message": "transaction completed" }
+ '33027': InvalidOrder, // { "code": 33027, "message": "cancelled order or order cancelling" }
+ '33028': InvalidOrder, // { "code": 33028, "message": "the decimal places of the trading price exceeded the limit" }
+ '33029': InvalidOrder, // { "code": 33029, "message": "the decimal places of the trading size exceeded the limit" }
+ '33034': ExchangeError, // { "code": 33034, "message": "You can only place limit order after Call Auction has started" }
+ '33035': ExchangeError, // This type of order cannot be canceled(This type of order cannot be canceled)
+ '33036': ExchangeError, // Exceeding the limit of entrust order
+ '33037': ExchangeError, // The buy order price should be lower than 130% of the trigger price
+ '33038': ExchangeError, // The sell order price should be higher than 70% of the trigger price
+ '33039': ExchangeError, // The limit of callback rate is 0 < x <= 5%
+ '33040': ExchangeError, // The trigger price of a buy order should be lower than the latest transaction price
+ '33041': ExchangeError, // The trigger price of a sell order should be higher than the latest transaction price
+ '33042': ExchangeError, // The limit of price variance is 0 < x <= 1%
+ '33043': ExchangeError, // The total amount must be larger than 0
+ '33044': ExchangeError, // The average amount should be 1/1000 * total amount <= x <= total amount
+ '33045': ExchangeError, // The price should not be 0, including trigger price, order price, and price limit
+ '33046': ExchangeError, // Price variance should be 0 < x <= 1%
+ '33047': ExchangeError, // Sweep ratio should be 0 < x <= 100%
+ '33048': ExchangeError, // Per order limit: Total amount/1000 < x <= Total amount
+ '33049': ExchangeError, // Total amount should be X > 0
+ '33050': ExchangeError, // Time interval should be 5 <= x <= 120s
+ '33051': ExchangeError, // cancel order number not higher limit: plan and track entrust no more than 10, ice and time entrust no more than 6
+ '33059': BadRequest, // { "code": 33059, "message": "client_oid or order_id is required" }
+ '33060': BadRequest, // { "code": 33060, "message": "Only fill in either parameter client_oid or order_id" }
+ '33061': ExchangeError, // Value of a single market price order cannot exceed 100,000 USD
+ '33062': ExchangeError, // The leverage ratio is too high. The borrowed position has exceeded the maximum position of this leverage ratio. Please readjust the leverage ratio
+ '33063': ExchangeError, // Leverage multiple is too low, there is insufficient margin in the account, please readjust the leverage ratio
+ '33064': ExchangeError, // The setting of the leverage ratio cannot be less than 2, please readjust the leverage ratio
+ '33065': ExchangeError, // Leverage ratio exceeds maximum leverage ratio, please readjust leverage ratio
+ // account
+ '21009': ExchangeError, // Funds cannot be transferred out within 30 minutes after swap settlement(Funds cannot be transferred out within 30 minutes after swap settlement)
+ '34001': PermissionDenied, // { "code": 34001, "message": "withdrawal suspended" }
+ '34002': InvalidAddress, // { "code": 34002, "message": "please add a withdrawal address" }
+ '34003': ExchangeError, // { "code": 34003, "message": "sorry, this token cannot be withdrawn to xx at the moment" }
+ '34004': ExchangeError, // { "code": 34004, "message": "withdrawal fee is smaller than minimum limit" }
+ '34005': ExchangeError, // { "code": 34005, "message": "withdrawal fee exceeds the maximum limit" }
+ '34006': ExchangeError, // { "code": 34006, "message": "withdrawal amount is lower than the minimum limit" }
+ '34007': ExchangeError, // { "code": 34007, "message": "withdrawal amount exceeds the maximum limit" }
+ '34008': InsufficientFunds, // { "code": 34008, "message": "insufficient balance" }
+ '34009': ExchangeError, // { "code": 34009, "message": "your withdrawal amount exceeds the daily limit" }
+ '34010': ExchangeError, // { "code": 34010, "message": "transfer amount must be larger than 0" }
+ '34011': ExchangeError, // { "code": 34011, "message": "conditions not met" }
+ '34012': ExchangeError, // { "code": 34012, "message": "the minimum withdrawal amount for NEO is 1, and the amount must be an integer" }
+ '34013': ExchangeError, // { "code": 34013, "message": "please transfer" }
+ '34014': ExchangeError, // { "code": 34014, "message": "transfer limited" }
+ '34015': ExchangeError, // { "code": 34015, "message": "subaccount does not exist" }
+ '34016': PermissionDenied, // { "code": 34016, "message": "transfer suspended" }
+ '34017': AccountSuspended, // { "code": 34017, "message": "account suspended" }
+ '34018': AuthenticationError, // { "code": 34018, "message": "incorrect trades password" }
+ '34019': PermissionDenied, // { "code": 34019, "message": "please bind your email before withdrawal" }
+ '34020': PermissionDenied, // { "code": 34020, "message": "please bind your funds password before withdrawal" }
+ '34021': InvalidAddress, // { "code": 34021, "message": "Not verified address" }
+ '34022': ExchangeError, // { "code": 34022, "message": "Withdrawals are not available for sub accounts" }
+ '34023': PermissionDenied, // { "code": 34023, "message": "Please enable futures trading before transferring your funds" }
+ '34026': ExchangeError, // transfer too frequently(transfer too frequently)
+ '34036': ExchangeError, // Parameter is incorrect, please refer to API documentation
+ '34037': ExchangeError, // Get the sub-account balance interface, account type is not supported
+ '34038': ExchangeError, // Since your C2C transaction is unusual, you are restricted from fund transfer. Please contact our customer support to cancel the restriction
+ '34039': ExchangeError, // You are now restricted from transferring out your funds due to abnormal trades on C2C Market. Please transfer your fund on our website or app instead to verify your identity
+ // swap
+ '35001': ExchangeError, // { "code": 35001, "message": "Contract does not exist" }
+ '35002': ExchangeError, // { "code": 35002, "message": "Contract settling" }
+ '35003': ExchangeError, // { "code": 35003, "message": "Contract paused" }
+ '35004': ExchangeError, // { "code": 35004, "message": "Contract pending settlement" }
+ '35005': AuthenticationError, // { "code": 35005, "message": "User does not exist" }
+ '35008': InvalidOrder, // { "code": 35008, "message": "Risk ratio too high" }
+ '35010': InvalidOrder, // { "code": 35010, "message": "Position closing too large" }
+ '35012': InvalidOrder, // { "code": 35012, "message": "Incorrect order size" }
+ '35014': InvalidOrder, // { "code": 35014, "message": "Order price is not within limit" }
+ '35015': InvalidOrder, // { "code": 35015, "message": "Invalid leverage level" }
+ '35017': ExchangeError, // { "code": 35017, "message": "Open orders exist" }
+ '35019': InvalidOrder, // { "code": 35019, "message": "Order size too large" }
+ '35020': InvalidOrder, // { "code": 35020, "message": "Order price too high" }
+ '35021': InvalidOrder, // { "code": 35021, "message": "Order size exceeded current tier limit" }
+ '35022': ExchangeError, // { "code": 35022, "message": "Contract status error" }
+ '35024': ExchangeError, // { "code": 35024, "message": "Contract not initialized" }
+ '35025': InsufficientFunds, // { "code": 35025, "message": "No account balance" }
+ '35026': ExchangeError, // { "code": 35026, "message": "Contract settings not initialized" }
+ '35029': OrderNotFound, // { "code": 35029, "message": "Order does not exist" }
+ '35030': InvalidOrder, // { "code": 35030, "message": "Order size too large" }
+ '35031': InvalidOrder, // { "code": 35031, "message": "Cancel order size too large" }
+ '35032': ExchangeError, // { "code": 35032, "message": "Invalid user status" }
+ '35037': ExchangeError, // No last traded price in cache
+ '35039': ExchangeError, // { "code": 35039, "message": "Open order quantity exceeds limit" }
+ '35040': InvalidOrder, // {"error_message":"Invalid order type","result":"true","error_code":"35040","order_id":"-1"}
+ '35044': ExchangeError, // { "code": 35044, "message": "Invalid order status" }
+ '35046': InsufficientFunds, // { "code": 35046, "message": "Negative account balance" }
+ '35047': InsufficientFunds, // { "code": 35047, "message": "Insufficient account balance" }
+ '35048': ExchangeError, // { "code": 35048, "message": "User contract is frozen and liquidating" }
+ '35049': InvalidOrder, // { "code": 35049, "message": "Invalid order type" }
+ '35050': InvalidOrder, // { "code": 35050, "message": "Position settings are blank" }
+ '35052': InsufficientFunds, // { "code": 35052, "message": "Insufficient cross margin" }
+ '35053': ExchangeError, // { "code": 35053, "message": "Account risk too high" }
+ '35055': InsufficientFunds, // { "code": 35055, "message": "Insufficient account balance" }
+ '35057': ExchangeError, // { "code": 35057, "message": "No last traded price" }
+ '35058': ExchangeError, // { "code": 35058, "message": "No limit" }
+ '35059': BadRequest, // { "code": 35059, "message": "client_oid or order_id is required" }
+ '35060': BadRequest, // { "code": 35060, "message": "Only fill in either parameter client_oid or order_id" }
+ '35061': BadRequest, // { "code": 35061, "message": "Invalid instrument_id" }
+ '35062': InvalidOrder, // { "code": 35062, "message": "Invalid match_price" }
+ '35063': InvalidOrder, // { "code": 35063, "message": "Invalid order_size" }
+ '35064': InvalidOrder, // { "code": 35064, "message": "Invalid client_oid" }
+ '35066': InvalidOrder, // Order interval error
+ '35067': InvalidOrder, // Time-weighted order ratio error
+ '35068': InvalidOrder, // Time-weighted order range error
+ '35069': InvalidOrder, // Time-weighted single transaction limit error
+ '35070': InvalidOrder, // Algo order type error
+ '35071': InvalidOrder, // Order total must be larger than single order limit
+ '35072': InvalidOrder, // Maximum 6 unfulfilled time-weighted orders can be held at the same time
+ '35073': InvalidOrder, // Order price is 0. Market-close-all not available
+ '35074': InvalidOrder, // Iceberg order single transaction average error
+ '35075': InvalidOrder, // Failed to cancel order
+ '35076': InvalidOrder, // LTC 20x leverage. Not allowed to open position
+ '35077': InvalidOrder, // Maximum 6 unfulfilled iceberg orders can be held at the same time
+ '35078': InvalidOrder, // Order amount exceeded 100,000
+ '35079': InvalidOrder, // Iceberg order price variance error
+ '35080': InvalidOrder, // Callback rate error
+ '35081': InvalidOrder, // Maximum 10 unfulfilled trail orders can be held at the same time
+ '35082': InvalidOrder, // Trail order callback rate error
+ '35083': InvalidOrder, // Each user can only hold a maximum of 10 unfulfilled stop-limit orders at the same time
+ '35084': InvalidOrder, // Order amount exceeded 1 million
+ '35085': InvalidOrder, // Order amount is not in the correct range
+ '35086': InvalidOrder, // Price exceeds 100 thousand
+ '35087': InvalidOrder, // Price exceeds 100 thousand
+ '35088': InvalidOrder, // Average amount error
+ '35089': InvalidOrder, // Price exceeds 100 thousand
+ '35090': ExchangeError, // No stop-limit orders available for cancelation
+ '35091': ExchangeError, // No trail orders available for cancellation
+ '35092': ExchangeError, // No iceberg orders available for cancellation
+ '35093': ExchangeError, // No trail orders available for cancellation
+ '35094': ExchangeError, // Stop-limit order last traded price error
+ '35095': BadRequest, // Instrument_id error
+ '35096': ExchangeError, // Algo order status error
+ '35097': ExchangeError, // Order status and order ID cannot exist at the same time
+ '35098': ExchangeError, // An order status or order ID must exist
+ '35099': ExchangeError, // Algo order ID error
+ // option
+ '36001': BadRequest, // Invalid underlying index.
+ '36002': BadRequest, // Instrument does not exist.
+ '36005': ExchangeError, // Instrument status is invalid.
+ '36101': AuthenticationError, // Account does not exist.
+ '36102': PermissionDenied, // Account status is invalid.
+ '36103': AccountSuspended, // Account is suspended due to ongoing liquidation.
+ '36104': PermissionDenied, // Account is not enabled for options trading.
+ '36105': PermissionDenied, // Please enable the account for option contract.
+ '36106': AccountSuspended, // Funds cannot be transferred in or out, as account is suspended.
+ '36107': PermissionDenied, // Funds cannot be transferred out within 30 minutes after option exercising or settlement.
+ '36108': InsufficientFunds, // Funds cannot be transferred in or out, as equity of the account is less than zero.
+ '36109': PermissionDenied, // Funds cannot be transferred in or out during option exercising or settlement.
+ '36201': PermissionDenied, // New order function is blocked.
+ '36202': PermissionDenied, // Account does not have permission to short option.
+ '36203': InvalidOrder, // Invalid format for client_oid.
+ '36204': ExchangeError, // Invalid format for request_id.
+ '36205': BadRequest, // Instrument id does not match underlying index.
+ '36206': BadRequest, // Order_id and client_oid can not be used at the same time.
+ '36207': InvalidOrder, // Either order price or fartouch price must be present.
+ '36208': InvalidOrder, // Either order price or size must be present.
+ '36209': InvalidOrder, // Either order_id or client_oid must be present.
+ '36210': InvalidOrder, // Either order_ids or client_oids must be present.
+ '36211': InvalidOrder, // Exceeding max batch size for order submission.
+ '36212': InvalidOrder, // Exceeding max batch size for oder cancellation.
+ '36213': InvalidOrder, // Exceeding max batch size for order amendment.
+ '36214': ExchangeError, // Instrument does not have valid bid/ask quote.
+ '36216': OrderNotFound, // Order does not exist.
+ '36217': InvalidOrder, // Order submission failed.
+ '36218': InvalidOrder, // Order cancellation failed.
+ '36219': InvalidOrder, // Order amendment failed.
+ '36220': InvalidOrder, // Order is pending cancel.
+ '36221': InvalidOrder, // Order qty is not valid multiple of lot size.
+ '36222': InvalidOrder, // Order price is breaching highest buy limit.
+ '36223': InvalidOrder, // Order price is breaching lowest sell limit.
+ '36224': InvalidOrder, // Exceeding max order size.
+ '36225': InvalidOrder, // Exceeding max open order count for instrument.
+ '36226': InvalidOrder, // Exceeding max open order count for underlying.
+ '36227': InvalidOrder, // Exceeding max open size across all orders for underlying
+ '36228': InvalidOrder, // Exceeding max available qty for instrument.
+ '36229': InvalidOrder, // Exceeding max available qty for underlying.
+ '36230': InvalidOrder, // Exceeding max position limit for underlying.
+ // --------------------------------------------------------
+ // swap
+ '400': BadRequest, // Bad Request
+ '401': AuthenticationError, // Unauthorized access
+ '403': PermissionDenied, // Access prohibited
+ '404': BadRequest, // Request address does not exist
+ '405': BadRequest, // The HTTP Method is not supported
+ '415': BadRequest, // The current media type is not supported
+ '429': DDoSProtection, // Too many requests
+ '500': ExchangeNotAvailable, // System busy
+ '1001': RateLimitExceeded, // The request is too frequent and has been throttled
+ '1002': ExchangeError, // {0} verifications within 24 hours
+ '1003': ExchangeError, // You failed more than {0} times today, the current operation is locked, please try again in 24 hours
+ // '00000': ExchangeError, // success
+ '40001': AuthenticationError, // ACCESS_KEY cannot be empty
+ '40002': AuthenticationError, // SECRET_KEY cannot be empty
+ '40003': AuthenticationError, // Signature cannot be empty
+ '40004': InvalidNonce, // Request timestamp expired
+ '40005': InvalidNonce, // Invalid ACCESS_TIMESTAMP
+ '40006': AuthenticationError, // Invalid ACCESS_KEY
+ '40007': BadRequest, // Invalid Content_Type
+ '40008': InvalidNonce, // Request timestamp expired
+ '40009': AuthenticationError, // sign signature error
+ '40010': AuthenticationError, // sign signature error
+ '40011': AuthenticationError, // ACCESS_PASSPHRASE cannot be empty
+ '40012': AuthenticationError, // apikey/password is incorrect
+ '40013': ExchangeError, // User status is abnormal
+ '40014': PermissionDenied, // Incorrect permissions
+ '40015': ExchangeError, // System is abnormal, please try again later
+ '40016': PermissionDenied, // The user must bind the phone or Google
+ '40017': ExchangeError, // Parameter verification failed
+ '40018': PermissionDenied, // Invalid IP
+ '40102': BadRequest, // Contract configuration does not exist, please check the parameters
+ '40103': BadRequest, // Request method cannot be empty
+ '40104': ExchangeError, // Lever adjustment failure
+ '40105': ExchangeError, // Abnormal access to current price limit data
+ '40106': ExchangeError, // Abnormal get next settlement time
+ '40107': ExchangeError, // Abnormal access to index price data
+ '40108': InvalidOrder, // Wrong order quantity
+ '40109': OrderNotFound, // The data of the order cannot be found, please confirm the order number
+ '40200': OnMaintenance, // Server upgrade, please try again later
+ '40201': InvalidOrder, // Order number cannot be empty
+ '40202': ExchangeError, // User information cannot be empty
+ '40203': BadRequest, // The amount of adjustment margin cannot be empty or negative
+ '40204': BadRequest, // Adjustment margin type cannot be empty
+ '40205': BadRequest, // Adjusted margin type data is wrong
+ '40206': BadRequest, // The direction of the adjustment margin cannot be empty
+ '40207': BadRequest, // The adjustment margin data is wrong
+ '40208': BadRequest, // The accuracy of the adjustment margin amount is incorrect
+ '40209': BadRequest, // The current page number is wrong, please confirm
+ '40300': ExchangeError, // User does not exist
+ '40301': PermissionDenied, // Permission has not been obtained yet. If you need to use it, please contact customer service
+ '40302': BadRequest, // Parameter abnormality
+ '40303': BadRequest, // Can only query up to 20,000 data
+ '40304': BadRequest, // Parameter type is abnormal
+ '40305': BadRequest, // Client_oid length is not greater than 50, and cannot be Martian characters
+ '40306': ExchangeError, // Batch processing orders can only process up to 20
+ '40308': OnMaintenance, // The contract is being temporarily maintained
+ '40309': BadSymbol, // The contract has been removed
+ '40400': ExchangeError, // Status check abnormal
+ '40401': ExchangeError, // The operation cannot be performed
+ '40402': BadRequest, // The opening direction cannot be empty
+ '40403': BadRequest, // Wrong opening direction format
+ '40404': BadRequest, // Whether to enable automatic margin call parameters cannot be empty
+ '40405': BadRequest, // Whether to enable the automatic margin call parameter type is wrong
+ '40406': BadRequest, // Whether to enable automatic margin call parameters is of unknown type
+ '40407': ExchangeError, // The query direction is not the direction entrusted by the plan
+ '40408': ExchangeError, // Wrong time range
+ '40409': ExchangeError, // Time format error
+ '40500': InvalidOrder, // Client_oid check error
+ '40501': ExchangeError, // Channel name error
+ '40502': ExchangeError, // If it is a copy user, you must pass the copy to whom
+ '40503': ExchangeError, // With the single type
+ '40504': ExchangeError, // Platform code must pass
+ '40505': ExchangeError, // Not the same as single type
+ '40506': AuthenticationError, // Platform signature error
+ '40507': AuthenticationError, // Api signature error
+ '40508': ExchangeError, // KOL is not authorized
+ '40509': ExchangeError, // Abnormal copy end
+ '40600': ExchangeError, // Copy function suspended
+ '40601': ExchangeError, // Followers cannot be KOL
+ '40602': ExchangeError, // The number of copies has reached the limit and cannot process the request
+ '40603': ExchangeError, // Abnormal copy end
+ '40604': ExchangeNotAvailable, // Server is busy, please try again later
+ '40605': ExchangeError, // Copy type, the copy number must be passed
+ '40606': ExchangeError, // The type of document number is wrong
+ '40607': ExchangeError, // Document number must be passed
+ '40608': ExchangeError, // No documented products currently supported
+ '40609': ExchangeError, // The contract product does not support copying
+ '40700': BadRequest, // Cursor parameters are incorrect
+ '40701': ExchangeError, // KOL is not authorized
+ '40702': ExchangeError, // Unauthorized copying user
+ '40703': ExchangeError, // Bill inquiry start and end time cannot be empty
+ '40704': ExchangeError, // Can only check the data of the last three months
+ '40705': BadRequest, // The start and end time cannot exceed 90 days
+ '40706': InvalidOrder, // Wrong order price
+ '40707': BadRequest, // Start time is greater than end time
+ '40708': BadRequest, // Parameter verification is abnormal
+ '40709': ExchangeError, // There is no position in this position, and no automatic margin call can be set
+ '40710': ExchangeError, // Abnormal account status
+ '40711': InsufficientFunds, // Insufficient contract account balance
+ '40712': InsufficientFunds, // Insufficient margin
+ '40713': ExchangeError, // Cannot exceed the maximum transferable margin amount
+ '40714': ExchangeError, // No direct margin call is allowed
+ // spot
+ 'invalid sign': AuthenticationError,
+ 'invalid currency': BadSymbol, // invalid trading pair
+ 'invalid symbol': BadSymbol,
+ 'invalid period': BadRequest, // invalid Kline type
+ 'invalid user': ExchangeError,
+ 'invalid amount': InvalidOrder,
+ 'invalid type': InvalidOrder, // {"status":"error","ts":1595700344504,"err_code":"invalid-parameter","err_msg":"invalid type"}
+ 'invalid orderId': InvalidOrder,
+ 'invalid record': ExchangeError,
+ 'invalid accountId': BadRequest,
+ 'invalid address': BadRequest,
+ 'accesskey not null': AuthenticationError, // {"status":"error","ts":1595704360508,"err_code":"invalid-parameter","err_msg":"accesskey not null"}
+ 'illegal accesskey': AuthenticationError,
+ 'sign not null': AuthenticationError,
+ 'req_time is too much difference from server time': InvalidNonce,
+ 'permissions not right': PermissionDenied, // {"status":"error","ts":1595704490084,"err_code":"invalid-parameter","err_msg":"permissions not right"}
+ 'illegal sign invalid': AuthenticationError, // {"status":"error","ts":1595684716042,"err_code":"invalid-parameter","err_msg":"illegal sign invalid"}
+ 'user locked': AccountSuspended,
+ 'Request Frequency Is Too High': RateLimitExceeded,
+ 'more than a daily rate of cash': BadRequest,
+ 'more than the maximum daily withdrawal amount': BadRequest,
+ 'need to bind email or mobile': ExchangeError,
+ 'user forbid': PermissionDenied,
+ 'User Prohibited Cash Withdrawal': PermissionDenied,
+ 'Cash Withdrawal Is Less Than The Minimum Value': BadRequest,
+ 'Cash Withdrawal Is More Than The Maximum Value': BadRequest,
+ 'the account with in 24 hours ban coin': PermissionDenied,
+ 'order cancel fail': BadRequest, // {"status":"error","ts":1595703343035,"err_code":"bad-request","err_msg":"order cancel fail"}
+ 'base symbol error': BadSymbol,
+ 'base date error': ExchangeError,
+ 'api signature not valid': AuthenticationError,
+ 'gateway internal error': ExchangeError,
+ 'audit failed': ExchangeError,
+ 'order queryorder invalid': BadRequest,
+ 'market no need price': InvalidOrder,
+ 'limit need price': InvalidOrder,
+ 'userid not equal to account_id': ExchangeError,
+ 'your balance is low': InsufficientFunds, // {"status":"error","ts":1595594160149,"err_code":"invalid-parameter","err_msg":"invalid size, valid range: [1,2000]"}
+ 'address invalid cointype': ExchangeError,
+ 'system exception': ExchangeError, // {"status":"error","ts":1595711862763,"err_code":"system exception","err_msg":"system exception"}
+ '50003': ExchangeError, // No record
+ '50004': BadSymbol, // The transaction pair is currently not supported or has been suspended
+ '50006': PermissionDenied, // The account is forbidden to withdraw. If you have any questions, please contact customer service.
+ '50007': PermissionDenied, // The account is forbidden to withdraw within 24 hours. If you have any questions, please contact customer service.
+ '50008': RequestTimeout, // network timeout
+ '50009': RateLimitExceeded, // The operation is too frequent, please try again later
+ '50010': ExchangeError, // The account is abnormally frozen. If you have any questions, please contact customer service.
+ '50014': InvalidOrder, // The transaction amount under minimum limits
+ '50015': InvalidOrder, // The transaction amount exceed maximum limits
+ '50016': InvalidOrder, // The price can't be higher than the current price
+ '50017': InvalidOrder, // Price under minimum limits
+ '50018': InvalidOrder, // The price exceed maximum limits
+ '50019': InvalidOrder, // The amount under minimum limits
+ '50020': InsufficientFunds, // Insufficient balance
+ '50021': InvalidOrder, // Price is under minimum limits
+ '50026': InvalidOrder, // Market price parameter error
+ 'invalid order query time': ExchangeError, // start time is greater than end time; or the time interval between start time and end time is greater than 48 hours
+ 'invalid start time': BadRequest, // start time is a date 30 days ago; or start time is a date in the future
+ 'invalid end time': BadRequest, // end time is a date 30 days ago; or end time is a date in the future
+ '20003': ExchangeError, // operation failed, {"status":"error","ts":1595730308979,"err_code":"bad-request","err_msg":"20003"}
+ '01001': ExchangeError, // order failed, {"status":"fail","err_code":"01001","err_msg":"系统异常,请稍后重试"}
+ },
+ 'broad': {
+ 'invalid size, valid range': ExchangeError,
+ },
+ },
+ 'precisionMode': TICK_SIZE,
+ 'options': {
+ 'createMarketBuyOrderRequiresPrice': true,
+ 'fetchMarkets': [
+ 'spot',
+ 'swap',
+ ],
+ 'parseOHLCV': {
+ 'volume': {
+ 'spot': 'amount',
+ 'swap': 5,
+ },
+ },
+ 'defaultType': 'spot', // 'spot', 'swap'
+ 'accountId': undefined, // '1012838157',
+ 'timeframes': {
+ 'spot': {
+ '1m': '1min',
+ '5m': '5min',
+ '15m': '15min',
+ '30m': '30min',
+ '1h': '60min',
+ '2h': '120min',
+ '4h': '240min',
+ '6h': '360min',
+ '12h': '720min',
+ '1d': '1day',
+ '1w': '1week',
+ },
+ 'swap': {
+ '1m': '60',
+ '5m': '300',
+ '15m': '900',
+ '30m': '1800',
+ '1h': '3600',
+ '2h': '7200',
+ '4h': '14400',
+ '6h': '21600',
+ '12h': '43200',
+ '1d': '86400',
+ '1w': '604800',
+ },
+ },
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.dataGetCommonTimestamp (params);
+ //
+ // {
+ // "status":"ok",
+ // "data":"1595525139400"
+ // }
+ //
+ return this.safeInteger (response, 'data');
+ }
+
+ async fetchMarkets (params = {}) {
+ let types = this.safeValue (this.options, 'fetchMarkets');
+ if (!types.length) {
+ types = [
+ this.options['defaultType'],
+ ];
+ }
+ let result = [];
+ for (let i = 0; i < types.length; i++) {
+ const markets = await this.fetchMarketsByType (types[i], params);
+ result = this.arrayConcat (result, markets);
+ }
+ return result;
+ }
+
+ parseMarkets (markets) {
+ const result = [];
+ for (let i = 0; i < markets.length; i++) {
+ result.push (this.parseMarket (markets[i]));
+ }
+ return result;
+ }
+
+ parseMarket (market) {
+ //
+ // spot
+ //
+ // {
+ // "base_currency":"btc",
+ // "quote_currency":"usdt",
+ // "symbol":"btc_usdt",
+ // "tick_size":"2",
+ // "size_increment":"4",
+ // "status":"1",
+ // "base_asset_precision":"8"
+ // }
+ //
+ //
+ // swap
+ //
+ // {
+ // "symbol":"btcusd",
+ // "underlying_index":"BTC",
+ // "quote_currency":"USD",
+ // "coin":"BTC",
+ // "contract_val":"1",
+ // "listing":null,
+ // "delivery":["07:00:00","15:00:00","23:00:00"],
+ // "size_increment":"0",
+ // "tick_size":"1",
+ // "forwardContractFlag":false,
+ // "priceEndStep":5
+ // }
+ //
+ const id = this.safeString (market, 'symbol');
+ let marketType = 'spot';
+ let spot = true;
+ let swap = false;
+ const baseId = this.safeString2 (market, 'base_currency', 'coin');
+ const quoteId = this.safeString (market, 'quote_currency');
+ const contractVal = this.safeFloat (market, 'contract_val');
+ if (contractVal !== undefined) {
+ marketType = 'swap';
+ spot = false;
+ swap = true;
+ }
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ let symbol = id.toUpperCase ();
+ if (spot) {
+ symbol = base + '/' + quote;
+ }
+ const tickSize = this.safeString (market, 'tick_size');
+ const sizeIncrement = this.safeString (market, 'size_increment');
+ const precision = {
+ 'amount': parseFloat ('1e-' + sizeIncrement),
+ 'price': parseFloat ('1e-' + tickSize),
+ };
+ const minAmount = this.safeFloat2 (market, 'min_size', 'base_min_size');
+ const status = this.safeString (market, 'status');
+ let active = undefined;
+ if (status !== undefined) {
+ active = (status === '1');
+ }
+ const fees = this.safeValue2 (this.fees, marketType, 'trading', {});
+ return this.extend (fees, {
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'info': market,
+ 'type': marketType,
+ 'spot': spot,
+ 'swap': swap,
+ 'active': active,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': minAmount,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': precision['price'],
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': precision['price'],
+ 'max': undefined,
+ },
+ },
+ });
+ }
+
+ async fetchMarketsByType (type, params = {}) {
+ if (type === 'spot') {
+ const response = await this.dataGetCommonSymbols (params);
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595526622408,
+ // "data":[
+ // {
+ // "base_currency":"btc",
+ // "quote_currency":"usdt",
+ // "symbol":"btc_usdt",
+ // "tick_size":"2",
+ // "size_increment":"4",
+ // "status":"1",
+ // "base_asset_precision":"8"
+ // },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseMarkets (data);
+ } else if (type === 'swap') {
+ const response = await this.capiGetMarketContracts (params);
+ //
+ // {
+ // "data":{
+ // "contractApis":[
+ // {
+ // "instrument_id":"btcusd",
+ // "underlying_index":"BTC",
+ // "quote_currency":"USD",
+ // "coin":"BTC",
+ // "contract_val":"1",
+ // "delivery":["07:00:00","15:00:00","23:00:00"],
+ // "size_increment":"0",
+ // "tick_size":"1",
+ // "forwardContractFlag":false,
+ // "priceEndStep":"5"
+ // },
+ // ]
+ // },
+ // "status":"ok",
+ // "err_code":"00000"
+ // }
+ //
+ return this.parseMarkets (response);
+ } else {
+ throw new NotSupported (this.id + ' fetchMarketsByType does not support market type ' + type);
+ }
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.dataGetCommonCurrencys (params);
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595537740466,
+ // "data":[
+ // "btc",
+ // "bft",
+ // "usdt",
+ // "usdt-omni",
+ // "usdt-erc20"
+ // ]
+ // }
+ //
+ const result = {};
+ const data = this.safeValue (response, 'data', []);
+ for (let i = 0; i < data.length; i++) {
+ const id = data[i];
+ const code = this.safeCurrencyCode (id);
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': id,
+ 'type': undefined,
+ 'name': undefined,
+ 'active': undefined,
+ 'fee': undefined,
+ 'precision': undefined,
+ 'limits': {
+ 'amount': { 'min': undefined, 'max': undefined },
+ 'price': { 'min': undefined, 'max': undefined },
+ 'cost': { 'min': undefined, 'max': undefined },
+ 'withdraw': { 'min': undefined, 'max': undefined },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ if (market['spot']) {
+ method = 'dataGetMarketDepth';
+ request['type'] = 'step0'; // step0, step1, step2, step3, step4, step5, do not merge depth if step0
+ } else if (market['swap']) {
+ method = 'capiGetMarketDepth';
+ request['limit'] = (limit === undefined) ? 100 : limit; // max 100
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ch":"market.btc_usdt.depth.step0",
+ // "ts":1595607628197,
+ // "data":{
+ // "id":"1595607628197",
+ // "ts":"1595607628197",
+ // "bids":[
+ // ["9534.99","15.36160000000000000000"],
+ // ["9534.85","0.14580000000000000000"],
+ // ["9534.73","0.02100000000000000000"],
+ // ],
+ // "asks":[
+ // ["9535.02","7.37160000000000000000"],
+ // ["9535.03","0.09040000000000000000"],
+ // ["9535.05","0.02180000000000000000"],
+ // ]
+ // }
+ // }
+ //
+ // swap
+ //
+ // {
+ // "asks":[
+ // ["9579.0","119865",1],
+ // ["9579.5","90069",1],
+ // ["9580.0","256673",1],
+ // ],
+ // "bids":[
+ // ["9578.5","2417",1],
+ // ["9577.5","3024",1],
+ // ["9577.0","21548",1],
+ // ],
+ // "timestamp":"1595664767349"
+ // }
+ //
+ const data = this.safeValue (response, 'data', response);
+ const timestamp = this.safeInteger2 (data, 'timestamp', 'ts');
+ const nonce = this.safeInteger (data, 'id');
+ const orderbook = this.parseOrderBook (data, timestamp);
+ orderbook['nonce'] = nonce;
+ return orderbook;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // spot
+ //
+ // fetchTicker
+ //
+ // {
+ // "id":"1595538241113",
+ // "bid":["0.028474000000","1.139400000000"],
+ // "ask":["0.028482000000","0.353100000000"],
+ // "amount":"2850.6649",
+ // "count":"818",
+ // "open":"0.02821",
+ // "close":"0.028474",
+ // "low":"0.02821",
+ // "high":"0.029091",
+ // "vol":"79.4548693404"
+ // }
+ //
+ // fetchTickers
+ //
+ // {
+ // "amount":"30086.8095",
+ // "count":"22450",
+ // "open":"9525.11",
+ // "close":"9591.81",
+ // "low":"9510.68",
+ // "high":"9659.7",
+ // "vol":"286239092.250461",
+ // "symbol":"btc_usdt"
+ // }
+ //
+ // swap
+ //
+ // {
+ // "instrument_id":"btcusd",
+ // "last":"9574.5",
+ // "best_ask":"9575.0",
+ // "best_bid":"9574.0",
+ // "high_24h":"9672",
+ // "low_24h":"9512",
+ // "volume_24h":"567697050",
+ // "timestamp":"1595538450096"
+ // }
+ //
+ const timestamp = this.safeInteger2 (ticker, 'timestamp', 'id');
+ let symbol = undefined;
+ const marketId = this.safeString2 (ticker, 'instrument_id', 'symbol');
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ symbol = market['symbol'];
+ } else if (marketId !== undefined) {
+ const parts = marketId.split ('_');
+ const numParts = parts.length;
+ if (numParts === 2) {
+ const [ baseId, quoteId ] = parts;
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ } else {
+ symbol = marketId;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ const last = this.safeFloat2 (ticker, 'last', 'close');
+ const open = this.safeFloat (ticker, 'open');
+ let bidVolume = undefined;
+ let askVolume = undefined;
+ let bid = this.safeValue (ticker, 'bid');
+ if (bid === undefined) {
+ bid = this.safeFloat (ticker, 'best_bid');
+ } else {
+ bidVolume = this.safeFloat (bid, 1);
+ bid = this.safeFloat (bid, 0);
+ }
+ let ask = this.safeValue (ticker, 'ask');
+ if (ask === undefined) {
+ ask = this.safeFloat (ticker, 'best_ask');
+ } else {
+ askVolume = this.safeFloat (ask, 1);
+ ask = this.safeFloat (ask, 0);
+ }
+ const baseVolume = this.safeFloat2 (ticker, 'amount', 'volume_24h');
+ const quoteVolume = this.safeFloat (ticker, 'vol');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ let change = undefined;
+ let percentage = undefined;
+ let average = undefined;
+ if ((last !== undefined) && (open !== undefined)) {
+ change = last - open;
+ percentage = change / open * 100;
+ average = this.sum (open, last) / 2;
+ }
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat2 (ticker, 'high', 'high_24h'),
+ 'low': this.safeFloat2 (ticker, 'low', 'low_24h'),
+ 'bid': bid,
+ 'bidVolume': bidVolume,
+ 'ask': ask,
+ 'askVolume': askVolume,
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ let method = undefined;
+ if (market['spot']) {
+ method = 'dataGetMarketDetailMerged';
+ } else if (market['swap']) {
+ method = 'capiGetMarketTicker';
+ }
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ch":"market.eth_btc.detail.merged",
+ // "ts":1595538241474,
+ // "data":{
+ // "id":"1595538241113",
+ // "bid":["0.028474000000","1.139400000000"],
+ // "ask":["0.028482000000","0.353100000000"],
+ // "amount":"2850.6649",
+ // "count":"818",
+ // "open":"0.02821",
+ // "close":"0.028474",
+ // "low":"0.02821",
+ // "high":"0.029091",
+ // "vol":"79.4548693404"
+ // }
+ // }
+ //
+ // swap
+ //
+ // {
+ // "symbol":"btcusd",
+ // "last":"9575.5",
+ // "best_ask":"9576.0",
+ // "best_bid":"9575.0",
+ // "high_24h":"9646",
+ // "low_24h":"9516",
+ // "volume_24h":"516656839",
+ // "timestamp":"1595664217405"
+ // }
+ //
+ const data = this.safeValue (response, 'data', response);
+ return this.parseTicker (data, market);
+ }
+
+ async fetchTickersByType (type, symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ let method = undefined;
+ if (type === 'spot') {
+ method = 'dataGetMarketTickers';
+ } else if (type === 'swap') {
+ method = 'capiGetMarketTickers';
+ }
+ const response = await this[method] (params);
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595542893250,
+ // "data":[
+ // {
+ // "amount":"30086.8095",
+ // "count":"22450",
+ // "open":"9525.11",
+ // "close":"9591.81",
+ // "low":"9510.68",
+ // "high":"9659.7",
+ // "vol":"286239092.250461",
+ // "symbol":"btc_usdt"
+ // }
+ // ]
+ // }
+ //
+ // swap
+ //
+ // [
+ // {
+ // "symbol":"btcusd",
+ // "last":"9572",
+ // "best_ask":"9571.5",
+ // "best_bid":"9570.5",
+ // "high_24h":"9646",
+ // "low_24h":"9516",
+ // "volume_24h":"515401635",
+ // "timestamp":"1595664479952"
+ // }
+ // ]
+ //
+ const data = this.safeValue (response, 'data', response);
+ let timestamp = undefined;
+ if (!Array.isArray (response)) {
+ timestamp = this.safeInteger (response, 'ts');
+ }
+ const result = {};
+ for (let i = 0; i < data.length; i++) {
+ const ticker = this.parseTicker (this.extend ({
+ 'timestamp': timestamp,
+ }, data[i]));
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ const defaultType = this.safeString2 (this.options, 'fetchTickers', 'defaultType');
+ const type = this.safeString (params, 'type', defaultType);
+ return await this.fetchTickersByType (type, symbols, this.omit (params, 'type'));
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // spot
+ //
+ // {
+ // "id":"1",
+ // "price":"9533.81",
+ // "amount":"0.7326",
+ // "direction":"sell",
+ // "ts":"1595604964000"
+ // }
+ //
+ // swap
+ //
+ // {
+ // "trade_id":"670581881367954915",
+ // "price":"9553.00",
+ // "size":"20",
+ // "side":"sell",
+ // "timestamp":"1595605100004",
+ // "symbol":"btcusd"
+ // }
+ //
+ // spot fetchMyTrades (private)
+ //
+ // {
+ // "id": 29555,
+ // "order_id": 59378,
+ // "match_id": 59335,
+ // "symbol": "eth_usdt",
+ // "type": "buy-limit",
+ // "source": "api",
+ // "price": "100.1000000000",
+ // "filled_amount": "0.9845000000",
+ // "filled_fees": "0.0019690000",
+ // "created_at": 1494901400487
+ // }
+ //
+ // fetchOrderTrades (private)
+ //
+ // spot
+ //
+ // {
+ // "id":"614164775",
+ // "created_at":"1596298860602",
+ // "filled_amount":"0.0417000000000000",
+ // "filled_fees":"0.0000834000000000",
+ // "match_id":"673491702661292033",
+ // "order_id":"673491720340279296",
+ // "price":"359.240000000000",
+ // "source":"接口",
+ // "symbol":"eth_usdt",
+ // "type":"buy-market"
+ // }
+ //
+ // swap
+ //
+ // {
+ // "trade_id":"6667390",
+ // "symbol":"cmt_btcusdt",
+ // "order_id":"525946425993854915",
+ // "price":"9839.00",
+ // "order_qty":"3466",
+ // "fee":"-0.0000528407360000",
+ // "timestamp":"1561121514442",
+ // "exec_type":"M",
+ // "side":"3"
+ // }
+ //
+ let symbol = undefined;
+ const marketId = this.safeString (trade, 'symbol');
+ let base = undefined;
+ let quote = undefined;
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ symbol = market['symbol'];
+ base = market['base'];
+ quote = market['quote'];
+ } else if (marketId !== undefined) {
+ const parts = marketId.split ('_');
+ const numParts = parts.length;
+ if (numParts === 2) {
+ const [ baseId, quoteId ] = parts;
+ base = this.safeCurrencyCode (baseId);
+ quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ } else {
+ symbol = marketId.toUpperCase ();
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ base = market['base'];
+ quote = market['quote'];
+ }
+ let timestamp = this.safeInteger (trade, 'created_at');
+ timestamp = this.safeInteger2 (trade, 'timestamp', 'ts', timestamp);
+ const price = this.safeFloat (trade, 'price');
+ let amount = this.safeFloat2 (trade, 'filled_amount', 'order_qty');
+ amount = this.safeFloat2 (trade, 'size', 'amount', amount);
+ let takerOrMaker = this.safeString2 (trade, 'exec_type', 'liquidity');
+ if (takerOrMaker === 'M') {
+ takerOrMaker = 'maker';
+ } else if (takerOrMaker === 'T') {
+ takerOrMaker = 'taker';
+ }
+ const orderType = this.safeString (trade, 'type');
+ let side = undefined;
+ let type = undefined;
+ if (orderType !== undefined) {
+ side = this.safeString (trade, 'type');
+ type = this.parseOrderType (side);
+ side = this.parseOrderSide (side);
+ } else {
+ side = this.safeString2 (trade, 'side', 'direction');
+ type = this.parseOrderType (side);
+ side = this.parseOrderSide (side);
+ }
+ let cost = undefined;
+ if (amount !== undefined) {
+ if (price !== undefined) {
+ cost = amount * price;
+ }
+ }
+ let feeCost = this.safeFloat (trade, 'fee');
+ if (feeCost === undefined) {
+ feeCost = this.safeFloat (trade, 'filled_fees');
+ } else {
+ feeCost = -feeCost;
+ }
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrency = (side === 'buy') ? base : quote;
+ fee = {
+ // fee is either a positive number (invitation rebate)
+ // or a negative number (transaction fee deduction)
+ // therefore we need to invert the fee
+ // more about it https://github.com/ccxt/ccxt/issues/5909
+ 'cost': feeCost,
+ 'currency': feeCurrency,
+ };
+ }
+ const orderId = this.safeString (trade, 'order_id');
+ const id = this.safeString2 (trade, 'trade_id', 'id');
+ return {
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'id': id,
+ 'order': orderId,
+ 'type': type,
+ 'takerOrMaker': takerOrMaker,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTrades (symbol, limit = undefined, since = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ if (market['spot']) {
+ method = 'dataGetMarketHistoryTrade';
+ } else if (market['swap']) {
+ method = 'capiGetMarketTrades';
+ }
+ if (market['spot']) {
+ if (limit !== undefined) {
+ request['size'] = limit; // default 1, max 2000
+ }
+ } else if (market['swap']) {
+ if (limit === undefined) {
+ limit = 100; // default 20, max 100
+ }
+ request['limit'] = limit;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ch":"market.btc_usdt.trade.detail",
+ // "ts":1595604968430,
+ // "data":{
+ // "ts":"1595604964000",
+ // "data":[
+ // {"id":"1","price":"9533.81","amount":"0.7326","direction":"sell","ts":"1595604964000"},
+ // {"id":"2","price":"9533.67","amount":"1.1591","direction":"buy","ts":"1595604961000"},
+ // {"id":"3","price":"9533.67","amount":"1.5022","direction":"sell","ts":"1595604959000"},
+ // ]
+ // }
+ // }
+ //
+ // swap
+ //
+ // [
+ // {"trade_id":"670833198971748613","price":"9578.50","size":"5412","side":"sell","timestamp":"1595665018790","symbol":"btcusd"},
+ // {"trade_id":"670833194240574915","price":"9579.00","size":"3972","side":"buy","timestamp":"1595665017662","symbol":"btcusd"},
+ // {"trade_id":"670833194240573915","price":"9579.00","size":"1227","side":"buy","timestamp":"1595665017662","symbol":"btcusd"},
+ // ]
+ //
+ let trades = undefined;
+ if (Array.isArray (response)) {
+ trades = response;
+ } else {
+ const data = this.safeValue (response, 'data', {});
+ trades = this.safeValue2 (data, 'data', []);
+ }
+ return this.parseTrades (trades, market, since, limit);
+ }
+
+ parseOHLCV (ohlcv, market = undefined, timeframe = '1m') {
+ //
+ // spot
+ //
+ // {
+ // "id":"1594694700000",
+ // "amount":"283.6811",
+ // "count":"234",
+ // "open":"9230.00",
+ // "close":"9227.15",
+ // "low":"9206.66",
+ // "high":"9232.33",
+ // "vol":"2618015.032504000000"
+ // }
+ //
+ // swap
+ //
+ // [
+ // "1594693800000",
+ // "9240",
+ // "9241",
+ // "9222",
+ // "9228.5",
+ // "3913370",
+ // "424.003616350563"
+ // ]
+ //
+ const options = this.safeValue (this.options, 'parseOHLCV', {});
+ const volume = this.safeValue (options, 'volume', {});
+ if (Array.isArray (ohlcv)) {
+ const volumeIndex = this.safeString (volume, market['type'], 'amount');
+ return [
+ this.safeInteger (ohlcv, 0), // timestamp
+ this.safeFloat (ohlcv, 1), // Open
+ this.safeFloat (ohlcv, 2), // High
+ this.safeFloat (ohlcv, 3), // Low
+ this.safeFloat (ohlcv, 4), // Close
+ // this.safeFloat (ohlcv, 5), // Quote Volume
+ // this.safeFloat (ohlcv, 6), // Base Volume
+ this.safeFloat (ohlcv, volumeIndex), // Volume, bitget will return base volume in the 7th element for future markets
+ ];
+ } else {
+ const volumeIndex = this.safeValue (volume, market['type'], 6);
+ return [
+ this.safeInteger (ohlcv, 'id'),
+ this.safeFloat (ohlcv, 'open'), // Open
+ this.safeFloat (ohlcv, 'high'), // High
+ this.safeFloat (ohlcv, 'low'), // Low
+ this.safeFloat (ohlcv, 'close'), // Close
+ this.safeFloat (ohlcv, volumeIndex), // Base Volume
+ ];
+ }
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ const type = market['type'];
+ const options = this.safeValue (this.options, 'timeframes', {});
+ const intervals = this.safeValue (options, type, {});
+ const interval = this.safeValue (intervals, this.timeframes[timeframe]);
+ if (market['spot']) {
+ method = 'dataGetMarketHistoryKline';
+ request['period'] = interval;
+ if (limit !== undefined) {
+ request['size'] = limit; // default 150, max 1000
+ }
+ } else if (market['swap']) {
+ const duration = this.parseTimeframe (timeframe);
+ method = 'capiGetMarketCandles';
+ request['granularity'] = interval;
+ const now = this.milliseconds ();
+ if (since === undefined) {
+ if (limit === undefined) {
+ limit = 1000;
+ }
+ request['start'] = this.iso8601 (now - limit * duration * 1000);
+ request['end'] = this.iso8601 (now);
+ } else {
+ request['start'] = this.iso8601 (since);
+ if (limit === undefined) {
+ request['end'] = this.iso8601 (now);
+ } else {
+ request['end'] = this.iso8601 (this.sum (since, limit * duration * 1000));
+ }
+ }
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ch":"market.btc_usdt.kline.15min",
+ // "ts":1595594183874,
+ // "data":[
+ // {"id":"1594694700000","amount":"283.6811","count":"234","open":"9230.00","close":"9227.15","low":"9206.66","high":"9232.33","vol":"2618015.032504000000"},
+ // {"id":"1594695600000","amount":"457.2904","count":"238","open":"9227.15","close":"9229.46","low":"9223.80","high":"9235.14","vol":"4220734.684570000000"},
+ // {"id":"1594696500000","amount":"501.2353","count":"255","open":"9229.46","close":"9227.78","low":"9222.69","high":"9230.74","vol":"4625779.185006000000"},
+ // ]
+ // }
+ //
+ // swap
+ //
+ // [
+ // ["1594764900000","9255.5","9261","9251","9255.5","3958946","427.742307964305"],
+ // ["1594765800000","9255.5","9264","9252","9258","3609496","389.832756058107"],
+ // ["1594766700000","9258","9260","9244.5","9250.5","3738600","403.97870345085"],
+ // ]
+ //
+ let candles = response;
+ if (!Array.isArray (response)) {
+ candles = this.safeValue (response, 'data', []);
+ }
+ return this.parseOHLCVs (candles, market, timeframe, since, limit);
+ }
+
+ parseSpotBalance (response) {
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595681450932,
+ // "data":{
+ // "list":[
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"trade"},
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"frozen"},
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"lock"},
+ // ],
+ // "id":"7420922606",
+ // "type":"spot",
+ // "state":"working"
+ // }
+ // }
+ //
+ const result = { 'info': response };
+ const data = this.safeValue (response, 'data');
+ const balances = this.safeValue (data, 'list');
+ for (let i = 0; i < balances.length; i++) {
+ const balance = balances[i];
+ const currencyId = this.safeString (balance, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ if (!(code in result)) {
+ const account = this.account ();
+ result[code] = account;
+ }
+ const type = this.safeValue (balance, 'type');
+ if (type === 'trade') {
+ result[code]['free'] = this.safeFloat (balance, 'balance');
+ } else if ((type === 'frozen') || (type === 'lock')) {
+ const used = this.safeFloat (result[code], 'used');
+ result[code]['used'] = this.sum (used, this.safeFloat (balance, 'balance'));
+ }
+ }
+ return this.parseBalance (result);
+ }
+
+ parseSwapBalance (response) {
+ //
+ // swap
+ //
+ // [
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"bchusd","margin_frozen":"0","timestamp":"1595673431547","margin_mode":"fixed","forwardContractFlag":false},
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"ethusd","margin_frozen":"0","timestamp":"1595673431573","margin_mode":"fixed","forwardContractFlag":false},
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"cmt_btcsusdt","margin_frozen":"0","timestamp":"1595673431577","margin_mode":"fixed","forwardContractFlag":true},
+ // ]
+ //
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const balance = response[i];
+ const marketId = this.safeString (balance, 'symbol');
+ let symbol = marketId;
+ if (marketId in this.markets_by_id) {
+ symbol = this.markets_by_id[marketId]['symbol'];
+ }
+ const account = this.account ();
+ // it may be incorrect to use total, free and used for swap accounts
+ account['total'] = this.safeFloat (balance, 'equity');
+ account['free'] = this.safeFloat (balance, 'total_avail_balance');
+ result[symbol] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchAccounts (params = {}) {
+ const request = {
+ 'method': 'accounts',
+ };
+ const response = await this.apiGetAccountAccounts (this.extend (request, params));
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595679591824,
+ // "data":[
+ // {"id":"7420922606","type":"spot","state":"working"}
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = [];
+ for (let i = 0; i < data.length; i++) {
+ const account = data[i];
+ const accountId = this.safeString (account, 'id');
+ const type = this.safeStringLower (account, 'type');
+ result.push ({
+ 'id': accountId,
+ 'type': type,
+ 'currency': undefined,
+ 'info': account,
+ });
+ }
+ return result;
+ }
+
+ async findAccountByType (type) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const accountsByType = this.groupBy (this.accounts, 'type');
+ const accounts = this.safeValue (accountsByType, type);
+ if (accounts === undefined) {
+ throw new ExchangeError (this.id + " findAccountByType() could not find an accountId with type '" + type + "', specify the 'accountId' parameter instead"); // eslint-disable-line quotes
+ }
+ const numAccounts = accounts.length;
+ if (numAccounts > 1) {
+ throw new ExchangeError (this.id + " findAccountByType() found more than one accountId with type '" + type + "', specify the 'accountId' parameter instead"); // eslint-disable-line quotes
+ }
+ return accounts[0];
+ }
+
+ async getAccountId (params) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const defaultAccountId = this.safeString (this.options, 'accountId');
+ const accountId = this.safeString (params, 'accountId', defaultAccountId);
+ if (accountId !== undefined) {
+ return accountId;
+ }
+ const defaultType = this.safeString (this.options, 'defaultType', 'margin');
+ const type = this.safeString (params, 'type', defaultType);
+ params = this.omit (params, 'type');
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " requires an 'accountId' parameter");
+ }
+ const account = await this.findAccountByType (type);
+ return account['id'];
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const defaultType = this.safeString2 (this.options, 'fetchBalance', 'defaultType');
+ const type = this.safeString (params, 'type', defaultType);
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " fetchBalance requires a 'type' parameter, one of 'spot', 'swap'");
+ }
+ let method = undefined;
+ const query = this.omit (params, 'type');
+ if (type === 'spot') {
+ const accountId = await this.getAccountId (params);
+ method = 'apiGetAccountsAccountIdBalance';
+ query['account_id'] = accountId;
+ query['method'] = 'balance';
+ } else if (type === 'swap') {
+ method = 'swapGetAccountAccounts';
+ }
+ const response = await this[method] (query);
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595681450932,
+ // "data":{
+ // "list":[
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"trade"},
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"frozen"},
+ // {"balance":"0.0000000000000000","currency":"BTC","type":"lock"},
+ // ],
+ // "id":"7420922606",
+ // "type":"spot",
+ // "state":"working"
+ // }
+ // }
+ //
+ // swap
+ //
+ // [
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"bchusd","margin_frozen":"0","timestamp":"1595673431547","margin_mode":"fixed","forwardContractFlag":false},
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"ethusd","margin_frozen":"0","timestamp":"1595673431573","margin_mode":"fixed","forwardContractFlag":false},
+ // {"equity":"0","fixed_balance":"0","total_avail_balance":"0","margin":"0","realized_pnl":"0","unrealized_pnl":"0","symbol":"cmt_btcsusdt","margin_frozen":"0","timestamp":"1595673431577","margin_mode":"fixed","forwardContractFlag":true},
+ // ]
+ //
+ return this.parseBalanceByType (type, response);
+ }
+
+ parseBalanceByType (type, response) {
+ if (type === 'spot') {
+ return this.parseSpotBalance (response);
+ } else if (type === 'swap') {
+ return this.parseSwapBalance (response);
+ }
+ throw new NotSupported (this.id + " fetchBalance does not support the '" + type + "' type (the type must be one of 'account', 'spot', 'margin', 'futures', 'swap')");
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'submitted': 'open',
+ 'partial-filled': 'open',
+ 'partial-canceled': 'canceled',
+ 'filled': 'closed',
+ 'canceled': 'canceled',
+ '-2': 'failed',
+ '-1': 'canceled',
+ '0': 'open',
+ '1': 'open',
+ '2': 'closed',
+ '3': 'open',
+ '4': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrderSide (side) {
+ const sides = {
+ 'buy-market': 'buy',
+ 'sell-market': 'sell',
+ 'buy-limit': 'buy',
+ 'sell-limit': 'sell',
+ '1': 'long', // open long
+ '2': 'short', // open short
+ '3': 'long', // close long
+ '4': 'short', // close short
+ };
+ return this.safeString (sides, side, side);
+ }
+
+ parseOrderType (type) {
+ const types = {
+ 'buy-market': 'market',
+ 'sell-market': 'market',
+ 'buy-limit': 'limit',
+ 'sell-limit': 'limit',
+ '1': 'open', // open long
+ '2': 'open', // open short
+ '3': 'close', // close long
+ '4': 'close', // close short
+ };
+ return this.safeString (types, type, type);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595792596056,
+ // "data":671368296142774272
+ // }
+ //
+ // swap
+ //
+ // {
+ // "client_oid":"58775e54-0592-491c-97e8-e2369025f2d1",
+ // "order_id":"671757564085534713"
+ // }
+ //
+ // cancelOrder
+ //
+ // spot
+ //
+ // {
+ // "status": "ok",
+ // "ts": 1595818631279,
+ // "data": 671368296142774272
+ // }
+ //
+ // swap
+ //
+ // {
+ // "order_id":"671757564085534713",
+ // "client_oid":"58775e54-0592-491c-97e8-e2369025f2d1",
+ // "symbol":"cmt_ethusdt",
+ // "result":true,
+ // "err_code":null,
+ // "err_msg":null
+ // }
+ //
+ // fetchOpenOrders, fetchClosedOrders, fetchOrder
+ //
+ // spot
+ //
+ // {
+ // "account_id":"7420922606",
+ // "amount":"0.1000000000000000",
+ // "canceled_at":"1595872129618",
+ // "created_at":"1595872089525",
+ // "filled_amount":"0.000000000000",
+ // "filled_cash_amount":"0.000000000000",
+ // "filled_fees":"0.000000000000",
+ // "finished_at":"1595872129618",
+ // "id":"671701716584665088",
+ // "price":"150.000000000000",
+ // "source":"接口",
+ // "state":"canceled",
+ // "symbol":"eth_usdt",
+ // "type":"buy-limit"
+ // }
+ //
+ // swap
+ //
+ // {
+ // "symbol":"cmt_ethusdt",
+ // "size":"1",
+ // "timestamp":"1595885546770",
+ // "client_oid":"f3aa81d6-9a4c-4eab-bebe-ebc19da21cf2",
+ // "createTime":"1595885521200",
+ // "filled_qty":"0",
+ // "fee":"0.00000000",
+ // "order_id":"671758053112020913",
+ // "price":"150.00",
+ // "price_avg":"0.00",
+ // "status":"0",
+ // "type":"1",
+ // "order_type":"0",
+ // "totalProfits":null
+ // }
+ //
+ let id = this.safeString (order, 'order_id');
+ id = this.safeString2 (order, 'id', 'data', id);
+ const timestamp = this.safeInteger2 (order, 'created_at', 'createTime');
+ let type = this.safeString (order, 'type');
+ const side = this.parseOrderSide (type);
+ type = this.parseOrderType (type);
+ // if ((side !== 'buy') && (side !== 'sell')) {
+ // side = this.parseOrderSide (type);
+ // }
+ // if ((type !== 'limit') && (type !== 'market')) {
+ // if ('pnl' in order) {
+ // type = 'futures';
+ // } else {
+ // type = 'swap';
+ // }
+ // }
+ let symbol = undefined;
+ const marketId = this.safeString (order, 'symbol');
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ symbol = marketId.toUpperCase ();
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ let amount = this.safeFloat2 (order, 'amount', 'size');
+ const filled = this.safeFloat2 (order, 'filled_amount', 'filled_qty');
+ let remaining = undefined;
+ if (amount !== undefined) {
+ if (filled !== undefined) {
+ amount = Math.max (amount, filled);
+ remaining = Math.max (0, amount - filled);
+ }
+ }
+ if (type === 'market') {
+ remaining = 0;
+ }
+ const cost = this.safeFloat (order, 'filled_cash_amount');
+ const price = this.safeFloat (order, 'price');
+ let average = this.safeFloat (order, 'price_avg');
+ if ((average === undefined) && (filled !== undefined) && (cost !== undefined) && (filled > 0)) {
+ average = cost / filled;
+ }
+ const status = this.parseOrderStatus (this.safeString2 (order, 'state', 'status'));
+ const feeCost = this.safeFloat2 (order, 'filled_fees', 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrency = undefined;
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrency,
+ };
+ }
+ const clientOrderId = this.safeString (order, 'client_oid');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'average': average,
+ 'cost': cost,
+ 'amount': amount,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': undefined,
+ };
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const market = this.market (symbol);
+ //
+ // spot
+ //
+ // account_id true string Account ID, obtained using the accounts method. Currency transactions use the accountid of the'spot' account; for loan asset transactions, please use the accountid of the'margin' account
+ // amount true string A limit order indicates the quantity of the order, when a market price buy order indicates how much money to buy, and when a market price sell order indicates how much currency to sell
+ // price false string Order price, market order does not pass this parameter
+ // source false string Order source api
+ // symbol true string Trading pair btc_usdt, eth_btc ...
+ // type true string Order Type buy-market: buy at market price, sell-market: sell at market price, buy-limit: buy at limit price, sell-limit: sell at limit price
+ //
+ // swap
+ //
+ // symbol String Yes Contract ID
+ // client_oid String Yes customize order IDs to identify your orders. (Less than 50 characters without special characters,
+ // size String Yes Quantity to buy or sell (value not equal to 0 or negative)
+ // type String Yes 1 Open long 2Open short 3 Close long 4 Close short
+ // order_type String Yes 0: Normal order (Unfilled and 0 imply normal limit order) 1: Post only 2: Fill or Kill 3: Immediate Or Cancel
+ // match_price String Yes 0 Limit price 1 market price
+ // price String No Price of each contract
+ //
+ const request = {
+ 'symbol': market['id'],
+ };
+ const clientOrderId = this.safeString2 (params, 'client_oid', 'clientOrderId', this.uuid ());
+ params = this.omit (params, [ 'client_oid', 'clientOrderId' ]);
+ let method = undefined;
+ if (market['spot']) {
+ const accountId = await this.getAccountId ({
+ 'type': market['type'],
+ });
+ method = 'apiPostOrderOrdersPlace';
+ request['account_id'] = accountId;
+ request['method'] = 'place';
+ request['type'] = side + '-' + type;
+ if (type === 'limit') {
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ request['price'] = this.priceToPrecision (symbol, price);
+ } else if (type === 'market') {
+ // for market buy it requires the amount of quote currency to spend
+ if (side === 'buy') {
+ let cost = this.safeFloat (params, 'amount');
+ const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true);
+ if (createMarketBuyOrderRequiresPrice) {
+ if (price !== undefined) {
+ if (cost === undefined) {
+ cost = amount * price;
+ }
+ } else if (cost === undefined) {
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument or in the 'amount' extra parameter (the exchange-specific behaviour)");
+ }
+ } else {
+ cost = (cost === undefined) ? amount : cost;
+ }
+ request['amount'] = this.costToPrecision (symbol, cost);
+ } else if (side === 'sell') {
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ }
+ }
+ // ...
+ } else if (market['swap']) {
+ request['order_type'] = '0'; // '0' = Normal order, undefined and 0 imply a normal limit order, '1' = Post only, '2' = Fill or Kill, '3' = Immediate Or Cancel
+ request['client_oid'] = clientOrderId;
+ const orderType = this.safeString (params, 'type');
+ if (orderType === undefined) {
+ throw new ArgumentsRequired (this.id + " createOrder requires a type parameter, '1' = open long, '2' = open short, '3' = close long, '4' = close short for " + market['type'] + ' orders');
+ }
+ request['size'] = this.amountToPrecision (symbol, amount);
+ request['type'] = orderType;
+ // if match_price is set to '1', the price parameter will be ignored for market orders
+ if (type === 'limit') {
+ request['match_price'] = '0';
+ request['price'] = this.priceToPrecision (symbol, price);
+ } else if (type === 'market') {
+ request['match_price'] = '1';
+ }
+ method = 'swapPostOrderPlaceOrder';
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595792596056,
+ // "data":"671368296142774272"
+ // }
+ //
+ // swap
+ //
+ // {
+ // "client_oid":"58775e54-0592-491c-97e8-e2369025f2d1",
+ // "order_id":"671757564085534713"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ let market = undefined;
+ let type = undefined;
+ if (symbol === undefined) {
+ const defaultType = this.safeString2 (this.options, 'cancelOrder', 'defaultType');
+ const type = this.safeString (params, 'type', defaultType);
+ if (type === 'spot') {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument for spot orders');
+ }
+ }
+ } else {
+ market = this.market (symbol);
+ type = market['type'];
+ }
+ const query = this.omit (params, 'type');
+ let method = undefined;
+ const request = {};
+ if (type === 'spot') {
+ method = 'apiPostOrderOrdersOrderIdSubmitcancel';
+ request['order_id'] = id;
+ request['method'] = 'submitcancel';
+ } else if (type === 'swap') {
+ method = 'swapPostOrderCancelOrder';
+ request['orderId'] = id;
+ request['symbol'] = market['id'];
+ }
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
+ //
+ // { "status": "ok", "ts": 1595818631279, "data": 671368296142774272 }
+ //
+ // swap
+ //
+ // {
+ // "order_id":"671757564085534713",
+ // "client_oid":"58775e54-0592-491c-97e8-e2369025f2d1",
+ // "symbol":"cmt_ethusdt",
+ // "result":true,
+ // "err_code":null,
+ // "err_msg":null
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrders (ids, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " cancelOrders requires a type parameter (one of 'spot', 'swap').");
+ }
+ const request = {};
+ let method = undefined;
+ if (type === 'spot') {
+ method = 'apiPostOrderOrdersBatchcancel';
+ request['method'] = 'batchcancel';
+ const jsonIds = this.json (ids);
+ const parts = jsonIds.split ('"');
+ request['order_ids'] = parts.join ('');
+ } else if (type === 'swap') {
+ method = 'swapPostOrderCancelBatchOrders';
+ request['symbol'] = market['id'];
+ request['ids'] = ids;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "status": "ok",
+ // "data": {
+ // "success": [
+ // "673451224205135872",
+ // ],
+ // "failed": [
+ // {
+ // "err-msg": "invalid record",
+ // "order-id": "673451224205135873",
+ // "err-code": "base record invalid"
+ // }
+ // ]
+ // }
+ // }
+ //
+ // swap
+ //
+ // {
+ // "result":true,
+ // "symbol":"cmt_btcusdt",
+ // "order_ids":[
+ // "258414711",
+ // "478585558"
+ // ],
+ // "fail_infos":[
+ // {
+ // "order_id":"258414711",
+ // "err_code":"401",
+ // "err_msg":""
+ // }
+ // ]
+ // }
+ //
+ return response;
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " fetchOrder requires a type parameter (one of 'spot', 'swap').");
+ }
+ let method = undefined;
+ const request = {};
+ if (type === 'spot') {
+ const clientOid = this.safeString (params, 'client_oid');
+ if (clientOid !== undefined) {
+ method = 'apiPostOrderOrdersClientOid';
+ request['client_oid'] = clientOid;
+ } else {
+ method = 'apiPostOrderOrdersOrderId';
+ request['order_id'] = id;
+ }
+ request['method'] = 'getOrder';
+ } else if (type === 'swap') {
+ method = 'swapGetOrderDetail';
+ request['symbol'] = market['id'];
+ request['orderId'] = id;
+ }
+ const query = this.omit (params, 'type');
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595897886717,
+ // "data":{
+ // "account_id":"7420922606",
+ // "amount":"0.1000000000000000",
+ // "canceled_at":"1595818631541",
+ // "created_at":"1595792595897",
+ // "filled_amount":"0.000000000000",
+ // "filled_cash_amount":"0.000000000000",
+ // "filled_fees":"0.000000000000",
+ // "finished_at":"1595818631541",
+ // "id":"671368296142774272",
+ // "price":"150.000000000000",
+ // "source":"接口",
+ // "state":"canceled",
+ // "symbol":"eth_usdt",
+ // "type":"buy-limit"
+ // }
+ // }
+ //
+ //
+ // swap
+ //
+ // {
+ // "symbol":"cmt_ethusdt",
+ // "size":"1",
+ // "timestamp":"1595896459890",
+ // "client_oid":"58775e54-0592-491c-97e8-e2369025f2d1",
+ // "createTime":"1595885404607",
+ // "filled_qty":"0",
+ // "fee":"0",
+ // "order_id":"671757564085534713",
+ // "price":"150",
+ // "price_avg":"0",
+ // "status":"-1",
+ // "type":"1",
+ // "order_type":"0",
+ // "totalProfits":"0"
+ // }
+ //
+ const data = this.safeValue (response, 'data', response);
+ return this.parseOrder (data, market);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ if (type === 'spot') {
+ method = 'apiGetOrderOrdersOpenOrders';
+ // request['from'] = this.safeString (params, 'from'); // order id
+ // request['direct'] = 'next'; // or 'prev'
+ request['method'] = 'openOrders';
+ if (limit === undefined) {
+ request['size'] = limit; // default 100, max 1000
+ }
+ } else if (type === 'swap') {
+ method = 'swapGetOrderOrders';
+ request['status'] = '3'; // 0 Failed, 1 Partially Filled, 2 Fully Filled 3 = Open + Partially Filled, 4 Canceling
+ request['from'] = '1';
+ request['to'] = '1';
+ if (limit === undefined) {
+ request['limit'] = 100; // default 100, max 100
+ }
+ }
+ const query = this.omit (params, 'type');
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
+ //
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595875165865,
+ // "data":[
+ // {
+ // "account_id":"7420922606",
+ // "amount":"0.1000000000000000",
+ // "canceled_at":"1595872129618",
+ // "created_at":"1595872089525",
+ // "filled_amount":"0.000000000000",
+ // "filled_cash_amount":"0.000000000000",
+ // "filled_fees":"0.000000000000",
+ // "finished_at":"1595872129618",
+ // "id":"671701716584665088",
+ // "price":"150.000000000000",
+ // "source":"接口",
+ // "state":"canceled",
+ // "symbol":"eth_usdt",
+ // "type":"buy-limit"
+ // }
+ // ]
+ // }
+ //
+ // swap
+ //
+ // [
+ // {
+ // "symbol":"cmt_ethusdt",
+ // "size":"1",
+ // "timestamp":"1595885546770",
+ // "client_oid":"f3aa81d6-9a4c-4eab-bebe-ebc19da21cf2",
+ // "createTime":"1595885521200",
+ // "filled_qty":"0",
+ // "fee":"0.00000000",
+ // "order_id":"671758053112020913",
+ // "price":"150.00",
+ // "price_avg":"0.00",
+ // "status":"0",
+ // "type":"1",
+ // "order_type":"0",
+ // "totalProfits":null
+ // }
+ // ]
+ //
+ let data = response;
+ if (!Array.isArray (response)) {
+ data = this.safeValue (response, 'data', []);
+ }
+ return this.parseOrders (data, market, undefined, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchClosedOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ if (type === 'spot') {
+ method = 'apiGetOrderOrdersHistory';
+ // Value range [((end_time) – 48h), (end_time)]
+ // the query window is 48 hours at most
+ // the window shift range is the last 30 days
+ if (since !== undefined) {
+ request['start_time'] = since;
+ }
+ // request['end_time'] = this.safeInteger (params, 'end_time');
+ // request['from'] = this.safeString (params, 'from'); // order id
+ // request['direct'] = 'next'; // or 'prev'
+ request['method'] = 'openOrders';
+ if (limit === undefined) {
+ request['size'] = limit; // default 100, max 1000
+ }
+ } else if (type === 'swap') {
+ method = 'swapGetOrderOrders';
+ request['status'] = '2'; // 0 Failed, 1 Partially Filled, 2 Fully Filled 3 = Open + Partially Filled, 4 Canceling
+ request['from'] = '1';
+ request['to'] = '1';
+ if (limit === undefined) {
+ request['limit'] = 100; // default 100, max 100
+ }
+ }
+ const query = this.omit (params, 'type');
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
+ //
+ //
+ // {
+ // "status":"ok",
+ // "ts":1595875165865,
+ // "data":[
+ // {
+ // "account_id":"7420922606",
+ // "amount":"0.1000000000000000",
+ // "canceled_at":"1595872129618",
+ // "created_at":"1595872089525",
+ // "filled_amount":"0.000000000000",
+ // "filled_cash_amount":"0.000000000000",
+ // "filled_fees":"0.000000000000",
+ // "finished_at":"1595872129618",
+ // "id":"671701716584665088",
+ // "price":"150.000000000000",
+ // "source":"接口",
+ // "state":"canceled",
+ // "symbol":"eth_usdt",
+ // "type":"buy-limit"
+ // }
+ // ]
+ // }
+ //
+ // swap
+ //
+ // [
+ // {
+ // "symbol":"cmt_ethusdt",
+ // "size":"1",
+ // "timestamp":"1595885546770",
+ // "client_oid":"f3aa81d6-9a4c-4eab-bebe-ebc19da21cf2",
+ // "createTime":"1595885521200",
+ // "filled_qty":"0",
+ // "fee":"0.00000000",
+ // "order_id":"671758053112020913",
+ // "price":"150.00",
+ // "price_avg":"0.00",
+ // "status":"0",
+ // "type":"1",
+ // "order_type":"0",
+ // "totalProfits":null
+ // }
+ // ]
+ //
+ let data = response;
+ if (!Array.isArray (response)) {
+ data = this.safeValue (response, 'data', []);
+ }
+ return this.parseOrders (data, market, undefined, limit);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchDeposits requires a currency code argument');
+ }
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ 'method': 'deposit_withdraw',
+ 'type': 'deposit',
+ 'size': 12,
+ };
+ const response = await this.apiGetOrderDepositWithdraw (this.extend (request, params));
+ //
+ // {
+ // "status": "ok",
+ // "data": [
+ // {
+ // "id": 1171,
+ // "type": "deposit",
+ // "currency": "usdt",
+ // "tx_hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
+ // "amount": 7.457467,
+ // "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
+ // "address_tag": "100040",
+ // "fee": 0,
+ // "state": "safe",
+ // "created_at": 1510912472199,
+ // "updated_at": 1511145876575
+ // },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTransactions (data, currency, since, limit, params);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchWithdrawals requires a currency code argument');
+ }
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ 'method': 'deposit_withdraw',
+ 'type': 'withdraw',
+ 'size': 12,
+ };
+ const response = await this.apiGetOrderDepositWithdraw (this.extend (request, params));
+ //
+ // {
+ // "status": "ok",
+ // "data": [
+ // {
+ // "id": 1171,
+ // "type": "withdraw",
+ // "currency": "usdt",
+ // "tx_hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
+ // "amount": 7.457467,
+ // "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
+ // "address_tag": "100040",
+ // "fee": 0,
+ // "state": "safe",
+ // "created_at": 1510912472199,
+ // "updated_at": 1511145876575
+ // },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTransactions (data, currency, since, limit, params);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ // withdrawals
+ 'WaitForOperation': 'pending', // 等待提现
+ 'OperationLock': 'pending', // 初审锁定成功
+ 'OperationSuccess': 'ok', // 提现成功
+ 'Cancel': 'canceled', // 用户撤销
+ 'Sure': 'ok', // 复审锁定成功
+ 'Fail': 'failed', // 出币异常
+ 'WaitForChainSure': 'ok', // 等待链上确认
+ // deposits
+ 'WAIT_0': 'pending', // 待确认
+ 'WAIT_1': 'pending', // 待确认
+ 'DATA_CHANGE': 'pending', // 待确认中
+ 'SUCCESS': 'ok', // 充值成功
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // fetchDeposits, fetchWithdrawals
+ //
+ // {
+ // "id": 1171,
+ // "type": "withdraw",
+ // "currency": "usdt",
+ // "tx_hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
+ // "amount": 7.457467,
+ // "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
+ // "address_tag": "100040",
+ // "fee": 0,
+ // "state": "safe",
+ // "created_at": 1510912472199,
+ // "updated_at": 1511145876575
+ // }
+ //
+ const id = this.safeString (transaction, 'id');
+ const address = this.safeString (transaction, 'address');
+ const tag = this.safeString (transaction, 'address_tag');
+ const tagFrom = undefined;
+ const tagTo = tag;
+ const addressFrom = undefined;
+ const addressTo = address;
+ let type = this.safeString (transaction, 'type');
+ if (type === 'withdraw') {
+ type = 'withdrawal';
+ } else if (type === 'deposit') {
+ type = 'deposit';
+ }
+ const currencyId = this.safeString (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const amount = this.safeFloat (transaction, 'amount');
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'state'));
+ const txid = this.safeString (transaction, 'tx_hash');
+ const timestamp = this.safeInteger (transaction, 'created_at');
+ const updated = this.safeInteger (transaction, 'updated_at');
+ const feeCost = this.safeFloat (transaction, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ fee = {
+ 'currency': code,
+ 'cost': feeCost,
+ };
+ }
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': code,
+ 'amount': amount,
+ 'addressFrom': addressFrom,
+ 'addressTo': addressTo,
+ 'address': address,
+ 'tagFrom': tagFrom,
+ 'tagTo': tagTo,
+ 'tag': tag,
+ 'status': status,
+ 'type': type,
+ 'updated': updated,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': fee,
+ };
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ const query = this.omit (params, 'type');
+ if (type === 'swap') {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades is not supported for ' + type + ' type');
+ }
+ //
+ // spot
+ //
+ // POST /api/v1/order/matchresults Query current order, order history
+ // symbol true string trading pair btc_usdt, eth_btc ...
+ // types false string Query order type combination buy-market, sell-market, buy-limit, sell-limit
+ // start_date false string Query start date, date format yyyy-mm-dd -61 days [-61day, end-date]
+ // end_date false string Query end date, date format yyyy-mm-dd Now [start-date, now]
+ // from false string Query start ID order record id
+ // direct false string Query direction ‘next’ is default , the transaction record ID is sorted from large to small prev,next
+ // size false string Query record size 100 <=100
+ //
+ const request = {
+ 'symbol': market['id'],
+ 'method': 'matchresults',
+ // 'types': 'buy-market,sell-market,buy-limit,sell-limit',
+ // 'start_date': this.ymd (since),
+ // 'end_date': this.ymd (this.milliseconds ()),
+ // 'size': 100,
+ // 'direct': 'next',
+ };
+ if (since !== undefined) {
+ request['start_date'] = this.ymd (since);
+ const end = this.sum (since, 2 * 24 * 60 * 60 * 1000);
+ request['end_date'] = this.ymd (end);
+ }
+ if (limit !== undefined) {
+ request['size'] = limit; // default 100, max 100
+ }
+ const response = await this.apiPostOrderMatchresults (this.extend (request, query));
+ //
+ // {
+ // "status": "ok",
+ // "data": [
+ // {
+ // "id": 29555,
+ // "order_id": 59378,
+ // "match_id": 59335,
+ // "symbol": "eth_usdt",
+ // "type": "buy-limit",
+ // "source": "api",
+ // "price": "100.1000000000",
+ // "filled_amount": "0.9845000000",
+ // "filled_fees": "0.0019690000",
+ // "created_at": 1494901400487
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrderTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = this.safeString (params, 'type', market['type']);
+ const query = this.omit (params, 'type');
+ let method = undefined;
+ const request = {};
+ if (type === 'spot') {
+ request['order_id'] = id;
+ request['method'] = 'matchresults';
+ method = 'apiPostOrderOrdersOrderIdMatchresults';
+ } else if (type === 'swap') {
+ request['orderId'] = id;
+ request['symbol'] = market['id'];
+ method = 'swapGetOrderFills';
+ }
+ const response = await this[method] (this.extend (request, query));
+ //
+ // spot
+ //
+ // {
+ // "status":"ok",
+ // "ts":1596298917277,
+ // "data":[
+ // {
+ // "id":"614164775",
+ // "created_at":"1596298860602",
+ // "filled_amount":"0.0417000000000000",
+ // "filled_fees":"0.0000834000000000",
+ // "match_id":"673491702661292033",
+ // "order_id":"673491720340279296",
+ // "price":"359.240000000000",
+ // "source":"接口",
+ // "symbol":"eth_usdt",
+ // "type":"buy-market"
+ // }
+ // ]
+ // }
+ //
+ // swap
+ //
+ //
+ // [
+ // {
+ // "trade_id":"6667390",
+ // "symbol":"cmt_btcusdt",
+ // "order_id":"525946425993854915",
+ // "price":"9839.00",
+ // "order_qty":"3466",
+ // "fee":"-0.0000528407360000",
+ // "timestamp":"1561121514442",
+ // "exec_type":"M",
+ // "side":"3"
+ // }
+ // ]
+ //
+ let data = response;
+ if (!Array.isArray (data)) {
+ data = this.safeValue (response, 'data', []);
+ }
+ return await this.parseTrades (data, market, since, limit);
+ }
+
+ async fetchPosition (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this.swapGetPositionSinglePosition (this.extend (request, params));
+ //
+ // {
+ // "margin_mode":"fixed", // Margin mode: crossed / fixed
+ // "holding":[
+ // {
+ // "symbol":"cmt_btcusdt", // Contract name
+ // "liquidation_price":"0.00", // Estimated liquidation price
+ // "position":"0", // Position Margin, the margin for holding current positions
+ // "avail_position":"0", // Available position
+ // "avg_cost":"0.00", // Transaction average price
+ // "leverage":"2", // Leverage
+ // "realized_pnl":"0.00000000", // Realized Profit and loss
+ // "keepMarginRate":"0.005", // Maintenance margin rate
+ // "side":"1", // Position Direction Long or short, Mark obsolete
+ // "holdSide":"1", // Position Direction Long or short
+ // "timestamp":"1557571623963", // System timestamp
+ // "margin":"0.0000000000000000", // Used margin
+ // "unrealized_pnl":"0.00000000", // Unrealized profit and loss
+ // }
+ // ]
+ // }
+ return response;
+ }
+
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.swapGetPositionAllPosition (params);
+ //
+ // [
+ // {
+ // "margin_mode":"fixed",
+ // "holding":[
+ // {
+ // "liquidation_price":"0.00",
+ // "position":"0",
+ // "avail_position":"0",
+ // "avg_cost":"0.00",
+ // "symbol":"btcusd",
+ // "leverage":"20",
+ // "keepMarginRate":"0.005",
+ // "realized_pnl":"0.00000000",
+ // "unrealized_pnl":"0",
+ // "side":"long",
+ // "holdSide":"1",
+ // "timestamp":"1595698564915",
+ // "margin":"0.0000000000000000"
+ // },
+ // ]
+ // },
+ // ]
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let request = '/' + this.implodeParams (path, params);
+ if ((api === 'capi') || (api === 'swap')) {
+ request = '/api/swap/' + this.version + request;
+ } else {
+ request = '/' + api + '/v1' + request;
+ }
+ let query = this.omit (params, this.extractParams (path));
+ let url = this.implodeParams (this.urls['api'][api], { 'hostname': this.hostname }) + request;
+ if ((api === 'data') || (api === 'capi')) {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (api === 'swap') {
+ this.checkRequiredCredentials ();
+ const timestamp = this.milliseconds ().toString ();
+ let auth = timestamp + method + request;
+ if (method === 'POST') {
+ body = this.json (params);
+ auth += body;
+ } else {
+ if (Object.keys (params).length) {
+ const query = this.urlencode (this.keysort (params));
+ url += '?' + query;
+ auth += '?' + query;
+ }
+ }
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256', 'base64');
+ headers = {
+ 'ACCESS-KEY': this.apiKey,
+ 'ACCESS-SIGN': signature,
+ 'ACCESS-TIMESTAMP': timestamp,
+ 'ACCESS-PASSPHRASE': this.password,
+ };
+ if (method === 'POST') {
+ headers['Content-Type'] = 'application/json';
+ }
+ } else if (api === 'api') {
+ const timestamp = this.milliseconds ().toString ();
+ let auth = '';
+ query = this.keysort (query);
+ auth = this.rawencode (query);
+ const hash = this.hash (this.encode (this.secret), 'sha1');
+ let signed = auth;
+ const signature = this.hmac (this.encode (auth), this.encode (hash), 'md5');
+ if (auth.length > 0) {
+ signed += '&';
+ }
+ signed += 'sign=' + signature + '&req_time=' + timestamp + '&accesskey=' + this.apiKey;
+ if (method === 'GET') {
+ if (Object.keys (query).length) {
+ url += '?' + signed;
+ }
+ } else if (method === 'POST') {
+ url += '?sign=' + signature + '&req_time=' + timestamp + '&accesskey=' + this.apiKey;
+ body = auth;
+ headers = {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ };
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (!response) {
+ return; // fallback to default error handler
+ }
+ //
+ // spot
+ //
+ // {"status":"fail","err_code":"01001","err_msg":"系统异常,请稍后重试"}
+ // {"status":"error","ts":1595594160149,"err_code":"invalid-parameter","err_msg":"invalid size, valid range: [1,2000]"}
+ // {"status":"error","ts":1595684716042,"err_code":"invalid-parameter","err_msg":"illegal sign invalid"}
+ // {"status":"error","ts":1595700216275,"err_code":"bad-request","err_msg":"your balance is low!"}
+ // {"status":"error","ts":1595700344504,"err_code":"invalid-parameter","err_msg":"invalid type"}
+ // {"status":"error","ts":1595703343035,"err_code":"bad-request","err_msg":"order cancel fail"}
+ // {"status":"error","ts":1595704360508,"err_code":"invalid-parameter","err_msg":"accesskey not null"}
+ // {"status":"error","ts":1595704490084,"err_code":"invalid-parameter","err_msg":"permissions not right"}
+ // {"status":"error","ts":1595711862763,"err_code":"system exception","err_msg":"system exception"}
+ // {"status":"error","ts":1595730308979,"err_code":"bad-request","err_msg":"20003"}
+ //
+ // swap
+ //
+ // {"code":"40015","msg":"","requestTime":1595698564931,"data":null}
+ // {"code":"40017","msg":"Order id must not be blank","requestTime":1595702477835,"data":null}
+ // {"code":"40017","msg":"Order Type must not be blank","requestTime":1595698516162,"data":null}
+ // {"code":"40301","msg":"","requestTime":1595667662503,"data":null}
+ // {"code":"40017","msg":"Contract code must not be blank","requestTime":1595703151651,"data":null}
+ // {"code":"40108","msg":"","requestTime":1595885064600,"data":null}
+ // {"order_id":"513468410013679613","client_oid":null,"symbol":"ethusd","result":false,"err_code":"order_no_exist_error","err_msg":"订单不存在!"}
+ //
+ const message = this.safeString (response, 'err_msg');
+ const errorCode = this.safeString2 (response, 'code', 'err_code');
+ const feedback = this.id + ' ' + body;
+ const nonEmptyMessage = ((message !== undefined) && (message !== ''));
+ if (nonEmptyMessage) {
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ }
+ const nonZeroErrorCode = (errorCode !== undefined) && (errorCode !== '00000');
+ if (nonZeroErrorCode) {
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ }
+ if (nonZeroErrorCode || nonEmptyMessage) {
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/bithumb.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bithumb.js
similarity index 85%
rename from TaskServer/node_modules/ccxt/js/bithumb.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bithumb.js
index 88324e947..904b8715d 100644
--- a/TaskServer/node_modules/ccxt/js/bithumb.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bithumb.js
@@ -4,6 +4,7 @@
const Exchange = require ('./base/Exchange');
const { ExchangeError, ExchangeNotAvailable, AuthenticationError, BadRequest, PermissionDenied, InvalidAddress, ArgumentsRequired, InvalidOrder } = require ('./base/errors');
+const { DECIMAL_PLACES, SIGNIFICANT_DIGITS, TRUNCATE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -15,13 +16,18 @@ module.exports = class bithumb extends Exchange {
'countries': [ 'KR' ], // South Korea
'rateLimit': 500,
'has': {
- 'CORS': true,
- 'createOrder': true,
'cancelOrder': true,
+ 'CORS': true,
'createMarketOrder': true,
- 'fetchTickers': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'urls': {
@@ -70,6 +76,7 @@ module.exports = class bithumb extends Exchange {
'taker': 0.25 / 100,
},
},
+ 'precisionMode': SIGNIFICANT_DIGITS,
'exceptions': {
'Bad Request(SSL)': BadRequest,
'Bad Request(Bad Method)': BadRequest,
@@ -88,19 +95,23 @@ module.exports = class bithumb extends Exchange {
});
}
+ amountToPrecision (symbol, amount) {
+ return this.decimalToPrecision (amount, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES);
+ }
+
async fetchMarkets (params = {}) {
const response = await this.publicGetTickerAll (params);
const data = this.safeValue (response, 'data');
const currencyIds = Object.keys (data);
const result = [];
+ const quote = this.safeCurrencyCode ('KRW');
for (let i = 0; i < currencyIds.length; i++) {
const currencyId = currencyIds[i];
if (currencyId === 'date') {
continue;
}
const market = data[currencyId];
- const base = currencyId;
- const quote = 'KRW';
+ const base = this.safeCurrencyCode (currencyId);
const symbol = currencyId + '/' + quote;
let active = true;
if (Array.isArray (market)) {
@@ -117,8 +128,8 @@ module.exports = class bithumb extends Exchange {
'info': market,
'active': active,
'precision': {
- 'amount': undefined,
- 'price': undefined,
+ 'amount': 4,
+ 'price': 4,
},
'limits': {
'amount': {
@@ -130,8 +141,8 @@ module.exports = class bithumb extends Exchange {
'max': undefined,
},
'cost': {
- 'min': undefined,
- 'max': undefined,
+ 'min': 500,
+ 'max': 5000000000,
},
},
'baseId': undefined,
@@ -236,10 +247,7 @@ module.exports = class bithumb extends Exchange {
}
const baseVolume = this.safeFloat (ticker, 'units_traded_24H');
const quoteVolume = this.safeFloat (ticker, 'acc_trade_value_24H');
- let vwap = undefined;
- if (quoteVolume !== undefined && baseVolume !== undefined) {
- vwap = quoteVolume / baseVolume;
- }
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -308,7 +316,7 @@ module.exports = class bithumb extends Exchange {
result[symbol] = this.parseTicker (ticker, market);
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -393,7 +401,7 @@ module.exports = class bithumb extends Exchange {
symbol = market['symbol'];
}
const price = this.safeFloat (trade, 'price');
- const amount = this.safeFloat (trade, 'units_traded');
+ const amount = this.safeFloat2 (trade, 'units_traded', 'units');
let cost = this.safeFloat (trade, 'total');
if (cost === undefined) {
if (amount !== undefined) {
@@ -503,25 +511,26 @@ module.exports = class bithumb extends Exchange {
// {
// "status": "0000",
// "data": {
- // "transaction_date": "1572497603668315",
- // "type": "bid",
- // "order_status": "Completed",
- // "order_currency": "BTC",
- // "payment_currency": "KRW",
- // "order_price": "8601000",
- // "order_qty": "0.007",
- // "cancel_date": "",
- // "cancel_type": "",
- // "contract": [
+ // order_date: '1603161798539254',
+ // type: 'ask',
+ // order_status: 'Cancel',
+ // order_currency: 'BTC',
+ // payment_currency: 'KRW',
+ // watch_price: '0',
+ // order_price: '13344000',
+ // order_qty: '0.0125',
+ // cancel_date: '1603161803809993',
+ // cancel_type: '사용자취소',
+ // contract: [
// {
- // "transaction_date": "1572497603902030",
- // "price": "8601000",
- // "units": "0.005",
- // "fee_currency": "KRW",
- // "fee": "107.51",
- // "total": "43005"
- // },
- // ]
+ // transaction_date: '1603161799976383',
+ // price: '13344000',
+ // units: '0.0015',
+ // fee_currency: 'KRW',
+ // fee: '0',
+ // total: '20016'
+ // }
+ // ],
// }
// }
//
@@ -539,6 +548,7 @@ module.exports = class bithumb extends Exchange {
}
parseOrder (order, market = undefined) {
+ //
//
// fetchOrder
//
@@ -564,6 +574,29 @@ module.exports = class bithumb extends Exchange {
// ]
// }
//
+ // {
+ // order_date: '1603161798539254',
+ // type: 'ask',
+ // order_status: 'Cancel',
+ // order_currency: 'BTC',
+ // payment_currency: 'KRW',
+ // watch_price: '0',
+ // order_price: '13344000',
+ // order_qty: '0.0125',
+ // cancel_date: '1603161803809993',
+ // cancel_type: '사용자취소',
+ // contract: [
+ // {
+ // transaction_date: '1603161799976383',
+ // price: '13344000',
+ // units: '0.0015',
+ // fee_currency: 'KRW',
+ // fee: '0',
+ // total: '20016'
+ // }
+ // ],
+ // }
+ //
// fetchOpenOrders
//
// {
@@ -592,14 +625,10 @@ module.exports = class bithumb extends Exchange {
if (remaining === undefined) {
if (status === 'closed') {
remaining = 0;
- } else {
+ } else if (status !== 'canceled') {
remaining = amount;
}
}
- let filled = undefined;
- if ((amount !== undefined) && (remaining !== undefined)) {
- filled = amount - remaining;
- }
let symbol = undefined;
const baseId = this.safeString (order, 'order_currency');
const quoteId = this.safeString (order, 'payment_currency');
@@ -611,35 +640,92 @@ module.exports = class bithumb extends Exchange {
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
+ let filled = undefined;
+ let cost = undefined;
+ let average = undefined;
+ const id = this.safeString (order, 'order_id');
const rawTrades = this.safeValue (order, 'contract');
let trades = undefined;
- const id = this.safeString (order, 'order_id');
+ let fee = undefined;
+ let fees = undefined;
+ let feesByCurrency = undefined;
if (rawTrades !== undefined) {
trades = this.parseTrades (rawTrades, market, undefined, undefined, {
'side': side,
'symbol': symbol,
'order': id,
});
+ filled = 0;
+ feesByCurrency = {};
+ for (let i = 0; i < trades.length; i++) {
+ const trade = trades[i];
+ filled = this.sum (filled, trade['amount']);
+ cost = this.sum (cost, trade['cost']);
+ const tradeFee = trade['fee'];
+ const feeCurrency = tradeFee['currency'];
+ if (feeCurrency in feesByCurrency) {
+ feesByCurrency[feeCurrency] = {
+ 'currency': feeCurrency,
+ 'cost': this.sum (feesByCurrency[feeCurrency]['cost'], tradeFee['cost']),
+ };
+ } else {
+ feesByCurrency[feeCurrency] = {
+ 'currency': feeCurrency,
+ 'cost': tradeFee['cost'],
+ };
+ }
+ }
+ const feeCurrencies = Object.keys (feesByCurrency);
+ const feeCurrenciesLength = feeCurrencies.length;
+ if (feeCurrenciesLength > 1) {
+ fees = [];
+ for (let i = 0; i < feeCurrencies.length; i++) {
+ const feeCurrency = feeCurrencies[i];
+ fees.push (feesByCurrency[feeCurrency]);
+ }
+ } else {
+ fee = this.safeValue (feesByCurrency, feeCurrencies[0]);
+ }
+ if (filled !== 0) {
+ average = cost / filled;
+ }
}
- return {
+ if (amount !== undefined) {
+ if ((filled === undefined) && (remaining !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ if ((remaining === undefined) && (filled !== undefined)) {
+ remaining = Math.max (0, amount - filled);
+ }
+ }
+ const result = {
'info': order,
'id': id,
+ 'clientOrderId': undefined,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
- 'cost': undefined,
- 'average': undefined,
+ 'cost': cost,
+ 'average': average,
'filled': filled,
'remaining': remaining,
'status': status,
'fee': undefined,
'trades': trades,
};
+ if (fee !== undefined) {
+ result['fee'] = fee;
+ } else if (fees !== undefined) {
+ result['fees'] = fees;
+ }
+ return result;
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -753,12 +839,12 @@ module.exports = class bithumb extends Exchange {
const nonce = this.nonce ().toString ();
const auth = endpoint + "\0" + body + "\0" + nonce; // eslint-disable-line quotes
const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha512');
- const signature64 = this.decode (this.stringToBase64 (this.encode (signature)));
+ const signature64 = this.decode (this.stringToBase64 (signature));
headers = {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded',
'Api-Key': this.apiKey,
- 'Api-Sign': signature64.toString (),
+ 'Api-Sign': signature64,
'Api-Nonce': nonce,
};
}
diff --git a/TaskServer/node_modules/ccxt/js/bitkk.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitkk.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/bitkk.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitkk.js
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitmart.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitmart.js
new file mode 100644
index 000000000..d99c5d095
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitmart.js
@@ -0,0 +1,2348 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { AuthenticationError, ExchangeNotAvailable, AccountSuspended, PermissionDenied, RateLimitExceeded, InvalidNonce, InvalidAddress, ArgumentsRequired, ExchangeError, InvalidOrder, InsufficientFunds, BadRequest, OrderNotFound, BadSymbol, NotSupported } = require ('./base/errors');
+const { ROUND, TICK_SIZE, TRUNCATE } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class bitmart extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'bitmart',
+ 'name': 'BitMart',
+ 'countries': [ 'US', 'CN', 'HK', 'KR' ],
+ 'rateLimit': 1000,
+ 'version': 'v1',
+ 'has': {
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'cancelOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchCanceledOrders': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchStatus': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
+ },
+ 'hostname': 'bitmart.com', // bitmart.info for Hong Kong users
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/61835713-a2662f80-ae85-11e9-9d00-6442919701fd.jpg',
+ 'api': 'https://api-cloud.{hostname}', // bitmart.info for Hong Kong users
+ 'www': 'https://www.bitmart.com/',
+ 'doc': 'https://github.com/bitmartexchange/bitmart-official-api-docs',
+ 'referral': 'http://www.bitmart.com/?r=rQCFLh',
+ 'fees': 'https://www.bitmart.com/fee/en',
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ 'uid': true,
+ },
+ 'api': {
+ 'public': {
+ 'system': {
+ 'get': [
+ 'time', // https://api-cloud.bitmart.com/system/time
+ 'service', // https://api-cloud.bitmart.com/system/service
+ ],
+ },
+ 'account': {
+ 'get': [
+ 'currencies', // https://api-cloud.bitmart.com/account/v1/currencies
+ ],
+ },
+ 'spot': {
+ 'get': [
+ 'currencies',
+ 'symbols',
+ 'symbols/details',
+ 'ticker', // ?symbol=BTC_USDT
+ 'steps', // ?symbol=BMX_ETH
+ 'symbols/kline', // ?symbol=BMX_ETH&step=15&from=1525760116&to=1525769116
+ 'symbols/book', // ?symbol=BMX_ETH&precision=6
+ 'symbols/trades', // ?symbol=BMX_ETH
+ ],
+ },
+ 'contract': {
+ 'get': [
+ 'contracts', // https://api-cloud.bitmart.com/contract/v1/ifcontract/contracts
+ 'pnls',
+ 'indexes',
+ 'tickers',
+ 'quote',
+ 'indexquote',
+ 'trades',
+ 'depth',
+ 'fundingrate',
+ ],
+ },
+ },
+ 'private': {
+ 'account': {
+ 'get': [
+ 'wallet', // ?account_type=1
+ 'deposit/address', // ?currency=USDT-TRC20
+ 'withdraw/charge', // ?currency=BTC
+ 'deposit-withdraw/history', // ?limit=10&offset=1&operationType=withdraw
+ 'deposit-withdraw/detail', // ?id=1679952
+ ],
+ 'post': [
+ 'withdraw/apply',
+ ],
+ },
+ 'spot': {
+ 'get': [
+ 'wallet',
+ 'order_detail',
+ 'orders',
+ 'trades',
+ ],
+ 'post': [
+ 'submit_order', // https://api-cloud.bitmart.com/spot/v1/submit_order
+ 'cancel_order', // https://api-cloud.bitmart.com/spot/v2/cancel_order
+ 'cancel_orders',
+ ],
+ },
+ 'contract': {
+ 'get': [
+ 'userOrders',
+ 'userOrderInfo',
+ 'userTrades',
+ 'orderTrades',
+ 'accounts',
+ 'userPositions',
+ 'userLiqRecords',
+ 'positionFee',
+ ],
+ 'post': [
+ 'batchOrders',
+ 'submitOrder',
+ 'cancelOrders',
+ 'marginOper',
+ ],
+ },
+ },
+ },
+ 'timeframes': {
+ '1m': 1,
+ '3m': 3,
+ '5m': 5,
+ '15m': 15,
+ '30m': 30,
+ '45m': 45,
+ '1h': 60,
+ '2h': 120,
+ '3h': 180,
+ '4h': 240,
+ '1d': 1440,
+ '1w': 10080,
+ '1M': 43200,
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.002,
+ 'maker': 0.001,
+ 'tiers': {
+ 'taker': [
+ [0, 0.20 / 100],
+ [10, 0.18 / 100],
+ [50, 0.16 / 100],
+ [250, 0.14 / 100],
+ [1000, 0.12 / 100],
+ [5000, 0.10 / 100],
+ [25000, 0.08 / 100],
+ [50000, 0.06 / 100],
+ ],
+ 'maker': [
+ [0, 0.1 / 100],
+ [10, 0.09 / 100],
+ [50, 0.08 / 100],
+ [250, 0.07 / 100],
+ [1000, 0.06 / 100],
+ [5000, 0.05 / 100],
+ [25000, 0.04 / 100],
+ [50000, 0.03 / 100],
+ ],
+ },
+ },
+ },
+ 'precisionMode': TICK_SIZE,
+ 'exceptions': {
+ 'exact': {
+ // general errors
+ '30000': ExchangeError, // 404, Not found
+ '30001': AuthenticationError, // 401, Header X-BM-KEY is empty
+ '30002': AuthenticationError, // 401, Header X-BM-KEY not found
+ '30003': AccountSuspended, // 401, Header X-BM-KEY has frozen
+ '30004': AuthenticationError, // 401, Header X-BM-SIGN is empty
+ '30005': AuthenticationError, // 401, Header X-BM-SIGN is wrong
+ '30006': AuthenticationError, // 401, Header X-BM-TIMESTAMP is empty
+ '30007': AuthenticationError, // 401, Header X-BM-TIMESTAMP range. Within a minute
+ '30008': AuthenticationError, // 401, Header X-BM-TIMESTAMP invalid format
+ '30010': PermissionDenied, // 403, IP is forbidden. We recommend enabling IP whitelist for API trading. After that reauth your account
+ '30011': AuthenticationError, // 403, Header X-BM-KEY over expire time
+ '30012': AuthenticationError, // 403, Header X-BM-KEY is forbidden to request it
+ '30013': RateLimitExceeded, // 429, Request too many requests
+ '30014': ExchangeNotAvailable, // 503, Service unavailable
+ // funding account errors
+ '60000': BadRequest, // 400, Invalid request (maybe the body is empty, or the int parameter passes string data)
+ '60001': BadRequest, // 400, Asset account type does not exist
+ '60002': BadRequest, // 400, currency does not exist
+ '60003': ExchangeError, // 400, Currency has been closed recharge channel, if there is any problem, please consult customer service
+ '60004': ExchangeError, // 400, Currency has been closed withdraw channel, if there is any problem, please consult customer service
+ '60005': ExchangeError, // 400, Minimum amount is %s
+ '60006': ExchangeError, // 400, Maximum withdraw precision is %d
+ '60007': InvalidAddress, // 400, Only withdrawals from added addresses are allowed
+ '60008': InsufficientFunds, // 400, Balance not enough
+ '60009': ExchangeError, // 400, Beyond the limit
+ '60010': ExchangeError, // 400, Withdraw id or deposit id not found
+ '60011': InvalidAddress, // 400, Address is not valid
+ '60012': ExchangeError, // 400, This action is not supported in this currency(If IOTA, HLX recharge and withdraw calls are prohibited)
+ '60020': PermissionDenied, // 403, Your account is not allowed to recharge
+ '60021': PermissionDenied, // 403, Your account is not allowed to withdraw
+ '60022': PermissionDenied, // 403, No withdrawals for 24 hours
+ '60030': BadRequest, // 405, Method Not Allowed
+ '60031': BadRequest, // 415, Unsupported Media Type
+ '60050': ExchangeError, // 500, User account not found
+ '60051': ExchangeError, // 500, Internal Server Error
+ // spot errors
+ '50000': BadRequest, // 400, Bad Request
+ '50001': BadSymbol, // 400, Symbol not found
+ '50002': BadRequest, // 400, From Or To format error
+ '50003': BadRequest, // 400, Step format error
+ '50004': BadRequest, // 400, Kline size over 500
+ '50005': OrderNotFound, // 400, Order Id not found
+ '50006': InvalidOrder, // 400, Minimum size is %s
+ '50007': InvalidOrder, // 400, Maximum size is %s
+ '50008': InvalidOrder, // 400, Minimum price is %s
+ '50009': InvalidOrder, // 400, Minimum count*price is %s
+ '50010': InvalidOrder, // 400, RequestParam size is required
+ '50011': InvalidOrder, // 400, RequestParam price is required
+ '50012': InvalidOrder, // 400, RequestParam notional is required
+ '50013': InvalidOrder, // 400, Maximum limit*offset is %d
+ '50014': BadRequest, // 400, RequestParam limit is required
+ '50015': BadRequest, // 400, Minimum limit is 1
+ '50016': BadRequest, // 400, Maximum limit is %d
+ '50017': BadRequest, // 400, RequestParam offset is required
+ '50018': BadRequest, // 400, Minimum offset is 1
+ '50019': BadRequest, // 400, Maximum price is %s
+ // '50019': ExchangeError, // 400, Invalid status. validate status is [1=Failed, 2=Success, 3=Frozen Failed, 4=Frozen Success, 5=Partially Filled, 6=Fully Fulled, 7=Canceling, 8=Canceled
+ '50020': InsufficientFunds, // 400, Balance not enough
+ '50021': BadRequest, // 400, Invalid %s
+ '50022': ExchangeNotAvailable, // 400, Service unavailable
+ '50023': BadSymbol, // 400, This Symbol can't place order by api
+ '53000': AccountSuspended, // 403, Your account is frozen due to security policies. Please contact customer service
+ '57001': BadRequest, // 405, Method Not Allowed
+ '58001': BadRequest, // 415, Unsupported Media Type
+ '59001': ExchangeError, // 500, User account not found
+ '59002': ExchangeError, // 500, Internal Server Error
+ // contract errors
+ '40001': ExchangeError, // 400, Cloud account not found
+ '40002': ExchangeError, // 400, out_trade_no not found
+ '40003': ExchangeError, // 400, out_trade_no already existed
+ '40004': ExchangeError, // 400, Cloud account count limit
+ '40005': ExchangeError, // 400, Transfer vol precision error
+ '40006': PermissionDenied, // 400, Invalid ip error
+ '40007': BadRequest, // 400, Parse parameter error
+ '40008': InvalidNonce, // 400, Check nonce error
+ '40009': BadRequest, // 400, Check ver error
+ '40010': BadRequest, // 400, Not found func error
+ '40011': BadRequest, // 400, Invalid request
+ '40012': ExchangeError, // 500, System error
+ '40013': ExchangeError, // 400, Access too often" CLIENT_TIME_INVALID, "Please check your system time.
+ '40014': BadSymbol, // 400, This contract is offline
+ '40015': BadSymbol, // 400, This contract's exchange has been paused
+ '40016': InvalidOrder, // 400, This order would trigger user position liquidate
+ '40017': InvalidOrder, // 400, It is not possible to open and close simultaneously in the same position
+ '40018': InvalidOrder, // 400, Your position is closed
+ '40019': ExchangeError, // 400, Your position is in liquidation delegating
+ '40020': InvalidOrder, // 400, Your position volume is not enough
+ '40021': ExchangeError, // 400, The position is not exsit
+ '40022': ExchangeError, // 400, The position is not isolated
+ '40023': ExchangeError, // 400, The position would liquidate when sub margin
+ '40024': ExchangeError, // 400, The position would be warnning of liquidation when sub margin
+ '40025': ExchangeError, // 400, The position’s margin shouldn’t be lower than the base limit
+ '40026': ExchangeError, // 400, You cross margin position is in liquidation delegating
+ '40027': InsufficientFunds, // 400, You contract account available balance not enough
+ '40028': PermissionDenied, // 400, Your plan order's count is more than system maximum limit.
+ '40029': InvalidOrder, // 400, The order's leverage is too large.
+ '40030': InvalidOrder, // 400, The order's leverage is too small.
+ '40031': InvalidOrder, // 400, The deviation between current price and trigger price is too large.
+ '40032': InvalidOrder, // 400, The plan order's life cycle is too long.
+ '40033': InvalidOrder, // 400, The plan order's life cycle is too short.
+ '40034': BadSymbol, // 400, This contract is not found
+ },
+ 'broad': {},
+ },
+ 'commonCurrencies': {
+ 'ONE': 'Menlo One',
+ 'PLA': 'Plair',
+ },
+ 'options': {
+ 'defaultType': 'spot', // 'spot', 'swap'
+ 'fetchBalance': {
+ 'type': 'spot', // 'spot', 'swap', 'contract', 'account'
+ },
+ 'createMarketBuyOrderRequiresPrice': true,
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicSystemGetTime (params);
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"c4e5e5b7-fe9f-4191-89f7-53f6c5bf9030",
+ // "data":{
+ // "server_time":1599843709578
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.safeInteger (data, 'server_time');
+ }
+
+ async fetchStatus (params = {}) {
+ const options = this.safeValue (this.options, 'fetchBalance', {});
+ const defaultType = this.safeString (this.options, 'defaultType');
+ let type = this.safeString (options, 'type', defaultType);
+ type = this.safeString (params, 'type', type);
+ params = this.omit (params, 'type');
+ const response = await this.publicSystemGetService (params);
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "serivce":[
+ // {
+ // "title": "Spot API Stop",
+ // "service_type": "spot",
+ // "status": "2",
+ // "start_time": 1527777538000,
+ // "end_time": 1527777538000
+ // },
+ // {
+ // "title": "Contract API Stop",
+ // "service_type": "contract",
+ // "status": "2",
+ // "start_time": 1527777538000,
+ // "end_time": 1527777538000
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const services = this.safeValue (data, 'service', []);
+ const servicesByType = this.indexBy (services, 'service_type');
+ if ((type === 'swap') || (type === 'future')) {
+ type = 'contract';
+ }
+ const service = this.safeValue (servicesByType, type);
+ let status = undefined;
+ let eta = undefined;
+ if (service !== undefined) {
+ const statusCode = this.safeInteger (service, 'status');
+ if (statusCode === 2) {
+ status = 'ok';
+ } else {
+ status = 'maintenance';
+ eta = this.safeInteger (service, 'end_time');
+ }
+ }
+ this.status = this.extend (this.status, {
+ 'status': status,
+ 'updated': this.milliseconds (),
+ 'eta': eta,
+ });
+ return this.status;
+ }
+
+ async fetchSpotMarkets (params = {}) {
+ const response = await this.publicSpotGetSymbolsDetails (params);
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"a67c9146-086d-4d3f-9897-5636a9bb26e1",
+ // "data":{
+ // "symbols":[
+ // {
+ // "symbol":"PRQ_BTC",
+ // "symbol_id":1232,
+ // "base_currency":"PRQ",
+ // "quote_currency":"BTC",
+ // "quote_increment":"1.0000000000",
+ // "base_min_size":"1.0000000000",
+ // "base_max_size":"10000000.0000000000",
+ // "price_min_precision":8,
+ // "price_max_precision":10,
+ // "expiration":"NA",
+ // "min_buy_amount":"0.0001000000",
+ // "min_sell_amount":"0.0001000000"
+ // },
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const symbols = this.safeValue (data, 'symbols', []);
+ const result = [];
+ for (let i = 0; i < symbols.length; i++) {
+ const market = symbols[i];
+ const id = this.safeString (market, 'symbol');
+ const numericId = this.safeInteger (market, 'symbol_id');
+ const baseId = this.safeString (market, 'base_currency');
+ const quoteId = this.safeString (market, 'quote_currency');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ //
+ // https://github.com/bitmartexchange/bitmart-official-api-docs/blob/master/rest/public/symbols_details.md#response-details
+ // from the above API doc:
+ // quote_increment Minimum order price as well as the price increment
+ // price_min_precision Minimum price precision (digit) used to query price and kline
+ // price_max_precision Maximum price precision (digit) used to query price and kline
+ //
+ // the docs are wrong: https://github.com/ccxt/ccxt/issues/5612
+ //
+ const pricePrecision = this.safeInteger (market, 'price_max_precision');
+ const precision = {
+ 'amount': this.safeFloat (market, 'base_min_size'),
+ 'price': parseFloat (this.decimalToPrecision (Math.pow (10, -pricePrecision), ROUND, 10)),
+ };
+ const minBuyCost = this.safeFloat (market, 'min_buy_amount');
+ const minSellCost = this.safeFloat (market, 'min_sell_amount');
+ const minCost = Math.max (minBuyCost, minSellCost);
+ const limits = {
+ 'amount': {
+ 'min': this.safeFloat (market, 'base_min_size'),
+ 'max': this.safeFloat (market, 'base_max_size'),
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': minCost,
+ 'max': undefined,
+ },
+ };
+ result.push ({
+ 'id': id,
+ 'numericId': numericId,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'type': 'spot',
+ 'spot': true,
+ 'future': false,
+ 'swap': false,
+ 'precision': precision,
+ 'limits': limits,
+ 'info': market,
+ 'active': undefined,
+ });
+ }
+ return result;
+ }
+
+ async fetchContractMarkets (params = {}) {
+ const response = await this.publicContractGetContracts (params);
+ //
+ // {
+ // "errno":"OK",
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"7fcedfb5-a660-4780-8a7a-b36a9e2159f7",
+ // "data":{
+ // "contracts":[
+ // {
+ // "contract":{
+ // "contract_id":1,
+ // "index_id":1,
+ // "name":"BTCUSDT",
+ // "display_name":"BTCUSDT永续合约",
+ // "display_name_en":"BTCUSDT_SWAP",
+ // "contract_type":1,
+ // "base_coin":"BTC",
+ // "quote_coin":"USDT",
+ // "price_coin":"BTC",
+ // "exchange":"*",
+ // "contract_size":"0.0001",
+ // "begin_at":"2018-08-17T04:00:00Z",
+ // "delive_at":"2020-08-15T12:00:00Z",
+ // "delivery_cycle":28800,
+ // "min_leverage":"1",
+ // "max_leverage":"100",
+ // "price_unit":"0.1",
+ // "vol_unit":"1",
+ // "value_unit":"0.0001",
+ // "min_vol":"1",
+ // "max_vol":"300000",
+ // "liquidation_warn_ratio":"0.85",
+ // "fast_liquidation_ratio":"0.8",
+ // "settgle_type":1,
+ // "open_type":3,
+ // "compensate_type":1,
+ // "status":3,
+ // "block":1,
+ // "rank":1,
+ // "created_at":"2018-07-12T19:16:57Z",
+ // "depth_bord":"1.001",
+ // "base_coin_zh":"比特币",
+ // "base_coin_en":"Bitcoin",
+ // "max_rate":"0.00375",
+ // "min_rate":"-0.00375"
+ // },
+ // "risk_limit":{"contract_id":1,"base_limit":"1000000","step":"500000","maintenance_margin":"0.005","initial_margin":"0.01"},
+ // "fee_config":{"contract_id":1,"maker_fee":"-0.0003","taker_fee":"0.001","settlement_fee":"0","created_at":"2018-07-12T20:47:22Z"},
+ // "plan_order_config":{"contract_id":0,"min_scope":"0.001","max_scope":"2","max_count":10,"min_life_cycle":24,"max_life_cycle":168}
+ // },
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const contracts = this.safeValue (data, 'contracts', []);
+ const result = [];
+ for (let i = 0; i < contracts.length; i++) {
+ const market = contracts[i];
+ const contract = this.safeValue (market, 'contract', {});
+ const id = this.safeString (contract, 'contract_id');
+ const numericId = this.safeInteger (contract, 'contract_id');
+ const baseId = this.safeString (contract, 'base_coin');
+ const quoteId = this.safeString (contract, 'quote_coin');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = this.safeString (contract, 'name');
+ //
+ // https://github.com/bitmartexchange/bitmart-official-api-docs/blob/master/rest/public/symbols_details.md#response-details
+ // from the above API doc:
+ // quote_increment Minimum order price as well as the price increment
+ // price_min_precision Minimum price precision (digit) used to query price and kline
+ // price_max_precision Maximum price precision (digit) used to query price and kline
+ //
+ // the docs are wrong: https://github.com/ccxt/ccxt/issues/5612
+ //
+ const amountPrecision = this.safeFloat (contract, 'vol_unit');
+ const pricePrecision = this.safeFloat (contract, 'price_unit');
+ const precision = {
+ 'amount': amountPrecision,
+ 'price': pricePrecision,
+ };
+ const limits = {
+ 'amount': {
+ 'min': this.safeFloat (contract, 'min_vol'),
+ 'max': this.safeFloat (contract, 'max_vol'),
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ };
+ const contractType = this.safeValue (contract, 'contract_type');
+ let future = false;
+ let swap = false;
+ let type = 'contract';
+ if (contractType === 1) {
+ type = 'swap';
+ swap = true;
+ } else if (contractType === 2) {
+ type = 'future';
+ future = true;
+ }
+ const feeConfig = this.safeValue (market, 'fee_config', {});
+ const maker = this.safeFloat (feeConfig, 'maker_fee');
+ const taker = this.safeFloat (feeConfig, 'taker_fee');
+ result.push ({
+ 'id': id,
+ 'numericId': numericId,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'maker': maker,
+ 'taker': taker,
+ 'type': type,
+ 'spot': false,
+ 'future': future,
+ 'swap': swap,
+ 'precision': precision,
+ 'limits': limits,
+ 'info': market,
+ 'active': undefined,
+ });
+ }
+ return result;
+ }
+
+ async fetchMarkets (params = {}) {
+ const spotMarkets = await this.fetchSpotMarkets ();
+ const contractMarkets = await this.fetchContractMarkets ();
+ const allMarkets = this.arrayConcat (spotMarkets, contractMarkets);
+ return allMarkets;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // spot
+ //
+ // {
+ // "symbol":"ETH_BTC",
+ // "last_price":"0.036037",
+ // "quote_volume_24h":"4380.6660000000",
+ // "base_volume_24h":"159.3582006712",
+ // "high_24h":"0.036972",
+ // "low_24h":"0.035524",
+ // "open_24h":"0.036561",
+ // "close_24h":"0.036037",
+ // "best_ask":"0.036077",
+ // "best_ask_size":"9.9500",
+ // "best_bid":"0.035983",
+ // "best_bid_size":"4.2792",
+ // "fluctuation":"-0.0143",
+ // "url":"https://www.bitmart.com/trade?symbol=ETH_BTC"
+ // }
+ //
+ // contract
+ //
+ // {
+ // "last_price":"422.2",
+ // "open":"430.5",
+ // "close":"422.2",
+ // "low":"421.9",
+ // "high":"436.9",
+ // "avg_price":"430.8569900089815372072",
+ // "volume":"2720",
+ // "total_volume":"18912248",
+ // "timestamp":1597631495,
+ // "rise_fall_rate":"-0.0192799070847851336",
+ // "rise_fall_value":"-8.3",
+ // "contract_id":2,
+ // "position_size":"3067404",
+ // "volume_day":"9557384",
+ // "amount24":"80995537.0919999999999974153",
+ // "base_coin_volume":"189122.48",
+ // "quote_coin_volume":"81484742.475833810590837937856",
+ // "pps":"1274350547",
+ // "index_price":"422.135",
+ // "fair_price":"422.147253318507",
+ // "depth_price":{"bid_price":"421.9","ask_price":"422","mid_price":"421.95"},
+ // "fair_basis":"0.000029027013",
+ // "fair_value":"0.012253318507",
+ // "rate":{"quote_rate":"0.0006","base_rate":"0.0003","interest_rate":"0.000099999999"},
+ // "premium_index":"0.000045851604",
+ // "funding_rate":"0.000158",
+ // "next_funding_rate":"0.000099999999",
+ // "next_funding_at":"2020-08-17T04:00:00Z"
+ // }
+ //
+ const timestamp = this.safeTimestamp (ticker, 'timestamp', this.milliseconds ());
+ const marketId = this.safeString2 (ticker, 'symbol', 'contract_id');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const last = this.safeFloat2 (ticker, 'close_24h', 'last_price');
+ let percentage = this.safeFloat (ticker, 'fluctuation', 'rise_fall_rate');
+ if (percentage !== undefined) {
+ percentage *= 100;
+ }
+ const baseVolume = this.safeFloat2 (ticker, 'base_volume_24h', 'base_coin_volume');
+ const quoteVolume = this.safeFloat2 (ticker, 'quote_volume_24h', 'quote_coin_volume');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ const open = this.safeFloat2 (ticker, 'open_24h', 'open');
+ let average = undefined;
+ if ((last !== undefined) && (open !== undefined)) {
+ average = this.sum (last, open) / 2;
+ }
+ average = this.safeFloat (ticker, 'avg_price', average);
+ const price = this.safeValue (ticker, 'depth_price', ticker);
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat2 (ticker, 'high', 'high_24h'),
+ 'low': this.safeFloat2 (ticker, 'low', 'low_24h'),
+ 'bid': this.safeFloat (price, 'best_bid', 'bid_price'),
+ 'bidVolume': this.safeFloat (ticker, 'best_bid_size'),
+ 'ask': this.safeFloat (price, 'best_ask', 'ask_price'),
+ 'askVolume': this.safeFloat (ticker, 'best_ask_size'),
+ 'vwap': vwap,
+ 'open': this.safeFloat (ticker, 'open_24h'),
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': undefined,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {};
+ let method = undefined;
+ if (market['swap'] || market['future']) {
+ method = 'publicContractGetTickers';
+ request['contractID'] = market['id'];
+ } else if (market['spot']) {
+ method = 'publicSpotGetTicker';
+ request['symbol'] = market['id'];
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"6aa5b923-2f57-46e3-876d-feca190e0b82",
+ // "data":{
+ // "tickers":[
+ // {
+ // "symbol":"ETH_BTC",
+ // "last_price":"0.036037",
+ // "quote_volume_24h":"4380.6660000000",
+ // "base_volume_24h":"159.3582006712",
+ // "high_24h":"0.036972",
+ // "low_24h":"0.035524",
+ // "open_24h":"0.036561",
+ // "close_24h":"0.036037",
+ // "best_ask":"0.036077",
+ // "best_ask_size":"9.9500",
+ // "best_bid":"0.035983",
+ // "best_bid_size":"4.2792",
+ // "fluctuation":"-0.0143",
+ // "url":"https://www.bitmart.com/trade?symbol=ETH_BTC"
+ // }
+ // ]
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "errno":"OK",
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"d09b57c4-d99b-4a13-91a8-2df98f889909",
+ // "data":{
+ // "tickers":[
+ // {
+ // "last_price":"422.2",
+ // "open":"430.5",
+ // "close":"422.2",
+ // "low":"421.9",
+ // "high":"436.9",
+ // "avg_price":"430.8569900089815372072",
+ // "volume":"2720",
+ // "total_volume":"18912248",
+ // "timestamp":1597631495,
+ // "rise_fall_rate":"-0.0192799070847851336",
+ // "rise_fall_value":"-8.3",
+ // "contract_id":2,
+ // "position_size":"3067404",
+ // "volume_day":"9557384",
+ // "amount24":"80995537.0919999999999974153",
+ // "base_coin_volume":"189122.48",
+ // "quote_coin_volume":"81484742.475833810590837937856",
+ // "pps":"1274350547",
+ // "index_price":"422.135",
+ // "fair_price":"422.147253318507",
+ // "depth_price":{"bid_price":"421.9","ask_price":"422","mid_price":"421.95"},
+ // "fair_basis":"0.000029027013",
+ // "fair_value":"0.012253318507",
+ // "rate":{"quote_rate":"0.0006","base_rate":"0.0003","interest_rate":"0.000099999999"},
+ // "premium_index":"0.000045851604",
+ // "funding_rate":"0.000158",
+ // "next_funding_rate":"0.000099999999",
+ // "next_funding_at":"2020-08-17T04:00:00Z"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const tickers = this.safeValue (data, 'tickers', []);
+ const tickersById = this.indexBy (tickers, 'symbol');
+ const ticker = this.safeValue (tickersById, market['id']);
+ return this.parseTicker (ticker, market);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const defaultType = this.safeString (this.options, 'defaultType', 'spot');
+ const type = this.safeString (params, 'type', defaultType);
+ params = this.omit (params, 'type');
+ let method = undefined;
+ if ((type === 'swap') || (type === 'future')) {
+ method = 'publicContractGetTickers';
+ } else if (type === 'spot') {
+ method = 'publicSpotGetTicker';
+ }
+ const response = await this[method] (params);
+ const data = this.safeValue (response, 'data', {});
+ const tickers = this.safeValue (data, 'tickers', []);
+ const result = {};
+ for (let i = 0; i < tickers.length; i++) {
+ const ticker = this.parseTicker (tickers[i]);
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicAccountGetCurrencies (params);
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"8c768b3c-025f-413f-bec5-6d6411d46883",
+ // "data":{
+ // "currencies":[
+ // {"currency":"MATIC","name":"Matic Network","withdraw_enabled":true,"deposit_enabled":true},
+ // {"currency":"KTN","name":"Kasoutuuka News","withdraw_enabled":true,"deposit_enabled":false},
+ // {"currency":"BRT","name":"Berith","withdraw_enabled":true,"deposit_enabled":true},
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const currencies = this.safeValue (data, 'currencies', []);
+ const result = {};
+ for (let i = 0; i < currencies.length; i++) {
+ const currency = currencies[i];
+ const id = this.safeString (currency, 'currency');
+ const code = this.safeCurrencyCode (id);
+ const name = this.safeString (currency, 'name');
+ const withdrawEnabled = this.safeValue (currency, 'withdraw_enabled');
+ const depositEnabled = this.safeValue (currency, 'deposit_enabled');
+ const active = withdrawEnabled && depositEnabled;
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'name': name,
+ 'info': currency, // the original payload
+ 'active': active,
+ 'fee': undefined,
+ 'precision': undefined,
+ 'limits': {
+ 'amount': { 'min': undefined, 'max': undefined },
+ 'price': { 'min': undefined, 'max': undefined },
+ 'cost': { 'min': undefined, 'max': undefined },
+ 'withdraw': { 'min': undefined, 'max': undefined },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {};
+ let method = undefined;
+ if (market['spot']) {
+ method = 'publicSpotGetSymbolsBook';
+ request['symbol'] = market['id'];
+ // request['precision'] = 4; // optional price precision / depth level whose range is defined in symbol details
+ } else if (market['swap'] || market['future']) {
+ method = 'publicContractGetDepth';
+ request['contractID'] = market['id'];
+ if (limit !== undefined) {
+ request['count'] = limit; // returns all records if size is omitted
+ }
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"8254f8fc-431d-404f-ad9a-e716339f66c7",
+ // "data":{
+ // "buys":[
+ // {"amount":"4.7091","total":"4.71","price":"0.034047","count":"1"},
+ // {"amount":"5.7439","total":"10.45","price":"0.034039","count":"1"},
+ // {"amount":"2.5249","total":"12.98","price":"0.032937","count":"1"},
+ // ],
+ // "sells":[
+ // {"amount":"41.4365","total":"41.44","price":"0.034174","count":"1"},
+ // {"amount":"4.2317","total":"45.67","price":"0.034183","count":"1"},
+ // {"amount":"0.3000","total":"45.97","price":"0.034240","count":"1"},
+ // ]
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "errno":"OK",
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"c330dfca-ca5b-4f15-b350-9fef3f049b4f",
+ // "data":{
+ // "sells":[
+ // {"price":"347.6","vol":"6678"},
+ // {"price":"347.7","vol":"3452"},
+ // {"price":"347.8","vol":"6331"},
+ // ],
+ // "buys":[
+ // {"price":"347.5","vol":"6222"},
+ // {"price":"347.4","vol":"20979"},
+ // {"price":"347.3","vol":"15179"},
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ if (market['spot']) {
+ return this.parseOrderBook (data, undefined, 'buys', 'sells', 'price', 'amount');
+ } else if (market['swap'] || market['future']) {
+ return this.parseOrderBook (data, undefined, 'buys', 'sells', 'price', 'vol');
+ }
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades spot
+ //
+ // {
+ // "amount":"0.005703",
+ // "order_time":1599652045394,
+ // "price":"0.034029",
+ // "count":"0.1676",
+ // "type":"sell"
+ // }
+ //
+ // public fetchTrades contract, private fetchMyTrades contract
+ //
+ // {
+ // "order_id":109159616160,
+ // "trade_id":109159616197,
+ // "contract_id":2,
+ // "deal_price":"347.6",
+ // "deal_vol":"5623",
+ // "make_fee":"-5.8636644",
+ // "take_fee":"9.772774",
+ // "created_at":"2020-09-09T11:49:50.749170536Z",
+ // "way":1,
+ // "fluctuation":"0"
+ // }
+ //
+ // private fetchMyTrades spot
+ //
+ // {
+ // "detail_id":256348632,
+ // "order_id":2147484350,
+ // "symbol":"BTC_USDT",
+ // "create_time":1590462303000,
+ // "side":"buy",
+ // "fees":"0.00001350",
+ // "fee_coin_name":"BTC",
+ // "notional":"88.00000000",
+ // "price_avg":"8800.00",
+ // "size":"0.01000",
+ // "exec_type":"M"
+ // }
+ //
+ const id = this.safeString2 (trade, 'trade_id', 'detail_id');
+ let timestamp = this.safeInteger2 (trade, 'order_time', 'create_time');
+ if (timestamp === undefined) {
+ timestamp = this.parse8601 (this.safeString (trade, 'created_at'));
+ }
+ const type = undefined;
+ const way = this.safeInteger (trade, 'way');
+ let side = this.safeStringLower2 (trade, 'type', 'side');
+ if ((side === undefined) && (way !== undefined)) {
+ if (way < 5) {
+ side = 'buy';
+ } else {
+ side = 'sell';
+ }
+ }
+ let takerOrMaker = undefined;
+ const execType = this.safeString (trade, 'exec_type');
+ if (execType !== undefined) {
+ takerOrMaker = (execType === 'M') ? 'maker' : 'taker';
+ }
+ let price = this.safeFloat2 (trade, 'price', 'deal_price');
+ price = this.safeFloat (trade, 'price_avg', price);
+ let amount = this.safeFloat2 (trade, 'amount', 'deal_vol');
+ amount = this.safeFloat (trade, 'size', amount);
+ let cost = this.safeFloat2 (trade, 'count', 'notional');
+ if ((cost === undefined) && (price !== undefined) && (amount !== undefined)) {
+ cost = amount * price;
+ }
+ const orderId = this.safeInteger (trade, 'order_id');
+ const marketId = this.safeString2 (trade, 'contract_id', 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const feeCost = this.safeFloat (trade, 'fees');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (trade, 'fee_coin_name');
+ let feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ if ((feeCurrencyCode === undefined) && (market !== undefined)) {
+ feeCurrencyCode = (side === 'buy') ? market['base'] : market['quote'];
+ }
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ return {
+ 'info': trade,
+ 'id': id,
+ 'order': orderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'type': type,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'takerOrMaker': takerOrMaker,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ let method = undefined;
+ if (market['spot']) {
+ request['symbol'] = market['id'];
+ method = 'publicSpotGetSymbolsTrades';
+ } else if (market['swap'] || market['future']) {
+ method = 'publicContractGetTrades';
+ request['contractID'] = market['id'];
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"222d74c0-8f6d-49d9-8e1b-98118c50eeba",
+ // "data":{
+ // "trades":[
+ // {
+ // "amount":"0.005703",
+ // "order_time":1599652045394,
+ // "price":"0.034029",
+ // "count":"0.1676",
+ // "type":"sell"
+ // },
+ // ]
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "errno":"OK",
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"782bc746-b86e-43bf-8d1a-c68b479c9bdd",
+ // "data":{
+ // "trades":[
+ // {
+ // "order_id":109159616160,
+ // "trade_id":109159616197,
+ // "contract_id":2,
+ // "deal_price":"347.6",
+ // "deal_vol":"5623",
+ // "make_fee":"-5.8636644",
+ // "take_fee":"9.772774",
+ // "created_at":"2020-09-09T11:49:50.749170536Z",
+ // "way":1,
+ // "fluctuation":"0"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'trades', []);
+ return this.parseTrades (trades, market, since, limit);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // spot
+ //
+ // {
+ // "last_price":"0.034987",
+ // "timestamp":1598787420,
+ // "volume":"1.0198",
+ // "open":"0.035007",
+ // "close":"0.034987",
+ // "high":"0.035007",
+ // "low":"0.034986"
+ // }
+ //
+ // contract
+ //
+ // {
+ // "low":"404.4",
+ // "high":"404.4",
+ // "open":"404.4",
+ // "close":"404.4",
+ // "last_price":"404.4",
+ // "avg_price":"404.4",
+ // "volume":"7670",
+ // "timestamp":1598758441,
+ // "rise_fall_rate":"0",
+ // "rise_fall_value":"0",
+ // "base_coin_volume":"76.7",
+ // "quote_coin_volume":"31017.48"
+ // }
+ //
+ return [
+ this.safeTimestamp (ohlcv, 'timestamp'),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'volume'),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const type = market['type'];
+ let method = undefined;
+ const request = {};
+ const duration = this.parseTimeframe (timeframe);
+ if (type === 'spot') {
+ method = 'publicSpotGetSymbolsKline';
+ request['symbol'] = market['id'];
+ request['step'] = this.timeframes[timeframe];
+ // the exchange will return an empty array if more than 500 candles is requested
+ const maxLimit = 500;
+ if (limit === undefined) {
+ limit = maxLimit;
+ }
+ limit = Math.min (maxLimit, limit);
+ if (since === undefined) {
+ const end = parseInt (this.milliseconds () / 1000);
+ const start = end - limit * duration;
+ request['from'] = start;
+ request['to'] = end;
+ } else {
+ const start = parseInt (since / 1000);
+ const end = this.sum (start, limit * duration);
+ request['from'] = start;
+ request['to'] = end;
+ }
+ } else if ((type === 'swap') || (type === 'future')) {
+ method = 'publicContractGetQuote';
+ request['contractID'] = market['id'];
+ const defaultLimit = 500;
+ if (limit === undefined) {
+ limit = defaultLimit;
+ }
+ if (since === undefined) {
+ const end = parseInt (this.milliseconds () / 1000);
+ const start = end - limit * duration;
+ request['startTime'] = start;
+ request['endTime'] = end;
+ } else {
+ const start = parseInt (since / 1000);
+ const end = this.sum (start, limit * duration);
+ request['startTime'] = start;
+ request['endTime'] = end;
+ }
+ request['unit'] = this.timeframes[timeframe];
+ request['resolution'] = 'M';
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"80d86378-ab4e-4c70-819e-b42146cf87ad",
+ // "data":{
+ // "klines":[
+ // {"last_price":"0.034987","timestamp":1598787420,"volume":"1.0198","open":"0.035007","close":"0.034987","high":"0.035007","low":"0.034986"},
+ // {"last_price":"0.034986","timestamp":1598787480,"volume":"0.3959","open":"0.034982","close":"0.034986","high":"0.034986","low":"0.034980"},
+ // {"last_price":"0.034978","timestamp":1598787540,"volume":"0.3259","open":"0.034987","close":"0.034978","high":"0.034987","low":"0.034977"},
+ // ]
+ // }
+ // }
+ //
+ // swap
+ //
+ // {
+ // "errno":"OK",
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"32965074-5804-4655-b693-e953e36026a0",
+ // "data":[
+ // {"low":"404.4","high":"404.4","open":"404.4","close":"404.4","last_price":"404.4","avg_price":"404.4","volume":"7670","timestamp":1598758441,"rise_fall_rate":"0","rise_fall_value":"0","base_coin_volume":"76.7","quote_coin_volume":"31017.48"},
+ // {"low":"404.1","high":"404.4","open":"404.4","close":"404.1","last_price":"404.1","avg_price":"404.15881086","volume":"12076","timestamp":1598758501,"rise_fall_rate":"-0.000741839762611276","rise_fall_value":"-0.3","base_coin_volume":"120.76","quote_coin_volume":"48806.2179994536"},
+ // {"low":"404","high":"404.3","open":"404.1","close":"404","last_price":"404","avg_price":"404.08918918","volume":"740","timestamp":1598758561,"rise_fall_rate":"-0.000247463499133878","rise_fall_value":"-0.1","base_coin_volume":"7.4","quote_coin_volume":"2990.259999932"},
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ if (Array.isArray (data)) {
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
+ } else {
+ const klines = this.safeValue (data, 'klines', []);
+ return this.parseOHLCVs (klines, market, timeframe, since, limit);
+ }
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ let method = undefined;
+ const request = {};
+ if (market['spot']) {
+ request['symbol'] = market['id'];
+ request['offset'] = 1;
+ if (limit === undefined) {
+ limit = 100; // max 100
+ }
+ request['limit'] = limit;
+ method = 'privateSpotGetTrades';
+ } else if (market['swap'] || market['future']) {
+ request['contractID'] = market['id'];
+ // request['offset'] = 1;
+ if (limit !== undefined) {
+ request['size'] = limit; // max 60
+ }
+ method = 'privateContractGetUserTrades';
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"a06a5c53-8e6f-42d6-8082-2ff4718d221c",
+ // "data":{
+ // "current_page":1,
+ // "trades":[
+ // {
+ // "detail_id":256348632,
+ // "order_id":2147484350,
+ // "symbol":"BTC_USDT",
+ // "create_time":1590462303000,
+ // "side":"buy",
+ // "fees":"0.00001350",
+ // "fee_coin_name":"BTC",
+ // "notional":"88.00000000",
+ // "price_avg":"8800.00",
+ // "size":"0.01000",
+ // "exec_type":"M"
+ // },
+ // ]
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "trades": [
+ // {
+ // "order_id": 10116361,
+ // "trade_id": 10116363,
+ // "contract_id": 1,
+ // "deal_price": "16",
+ // "deal_vol": "10",
+ // "make_fee": "0.04",
+ // "take_fee": "0.12",
+ // "created_at": null,
+ // "way": 5,
+ // "fluctuation": "0"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'trades', []);
+ return this.parseTrades (trades, market, since, limit);
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrderTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ let method = undefined;
+ const request = {};
+ if (market['spot']) {
+ request['symbol'] = market['id'];
+ request['order_id'] = id;
+ method = 'privateSpotGetTrades';
+ } else if (market['swap'] || market['future']) {
+ request['contractID'] = market['id'];
+ request['orderID'] = id;
+ method = 'privateContractGetOrderTrades';
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"a06a5c53-8e6f-42d6-8082-2ff4718d221c",
+ // "data":{
+ // "current_page":1,
+ // "trades":[
+ // {
+ // "detail_id":256348632,
+ // "order_id":2147484350,
+ // "symbol":"BTC_USDT",
+ // "create_time":1590462303000,
+ // "side":"buy",
+ // "fees":"0.00001350",
+ // "fee_coin_name":"BTC",
+ // "notional":"88.00000000",
+ // "price_avg":"8800.00",
+ // "size":"0.01000",
+ // "exec_type":"M"
+ // },
+ // ]
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "trades": [
+ // {
+ // "order_id": 10116361,
+ // "trade_id": 10116363,
+ // "contract_id": 1,
+ // "deal_price": "16",
+ // "deal_vol": "10",
+ // "make_fee": "0.04",
+ // "take_fee": "0.12",
+ // "created_at": null,
+ // "way": 5,
+ // "fluctuation": "0"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const trades = this.safeValue (data, 'trades', []);
+ return this.parseTrades (trades, market, since, limit);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ let method = undefined;
+ const options = this.safeValue (this.options, 'fetchBalance', {});
+ const defaultType = this.safeString (this.options, 'defaultType', 'spot');
+ let type = this.safeString (options, 'type', defaultType);
+ type = this.safeString (params, 'type', type);
+ params = this.omit (params, 'type');
+ if (type === 'spot') {
+ method = 'privateSpotGetWallet';
+ } else if (type === 'account') {
+ method = 'privateAccountGetWallet';
+ } else if ((type === 'swap') || (type === 'future') || (type === 'contract')) {
+ method = 'privateContractGetAccounts';
+ }
+ const response = await this[method] (params);
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"39069916-72f9-44c7-acde-2ad5afd21cad",
+ // "data":{
+ // "wallet":[
+ // {"id":"BTC","name":"Bitcoin","available":"0.00000062","frozen":"0.00000000"},
+ // {"id":"ETH","name":"Ethereum","available":"0.00002277","frozen":"0.00000000"},
+ // {"id":"BMX","name":"BitMart Token","available":"0.00000000","frozen":"0.00000000"}
+ // ]
+ // }
+ // }
+ //
+ // account
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"5c3b7fc7-93b2-49ef-bb59-7fdc56915b59",
+ // "data":{
+ // "wallet":[
+ // {"currency":"BTC","name":"Bitcoin","available":"0.00000062","frozen":"0.00000000"},
+ // {"currency":"ETH","name":"Ethereum","available":"0.00002277","frozen":"0.00000000"}
+ // ]
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "accounts": [
+ // {
+ // "account_id": 10,
+ // "coin_code": "USDT",
+ // "freeze_vol": "1201.8",
+ // "available_vol": "8397.65",
+ // "cash_vol": "0",
+ // "realised_vol": "-0.5",
+ // "unrealised_vol": "-0.5",
+ // "earnings_vol": "-0.5",
+ // "created_at": "2018-07-13T16:48:49+08:00",
+ // "updated_at": "2018-07-13T18:34:45.900387+08:00"
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const wallet = this.safeValue2 (data, 'wallet', 'accounts', []);
+ const result = { 'info': response };
+ for (let i = 0; i < wallet.length; i++) {
+ const balance = wallet[i];
+ let currencyId = this.safeString2 (balance, 'id', 'currency');
+ currencyId = this.safeString (balance, 'coind_code', currencyId);
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['free'] = this.safeFloat2 (balance, 'available', 'available_vol');
+ account['used'] = this.safeFloat2 (balance, 'frozen', 'freeze_vol');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // "order_id": 2707217580
+ // }
+ //
+ // cancelOrder
+ //
+ // '2707217580' // order id
+ //
+ // spot fetchOrder, fetchOrdersByStatus, fetchOpenOrders, fetchClosedOrders
+ //
+ // {
+ // "order_id":1736871726781,
+ // "symbol":"BTC_USDT",
+ // "create_time":1591096004000,
+ // "side":"sell",
+ // "type":"market",
+ // "price":"0.00",
+ // "price_avg":"0.00",
+ // "size":"0.02000",
+ // "notional":"0.00000000",
+ // "filled_notional":"0.00000000",
+ // "filled_size":"0.00000",
+ // "status":"8"
+ // }
+ //
+ // contract fetchOrder, fetchOrdersByStatus, fetchOpenOrders, fetchClosedOrders, fetchOrders
+ //
+ // {
+ // "order_id": 10539098,
+ // "contract_id": 1,
+ // "position_id": 10539088,
+ // "account_id": 10,
+ // "price": "16",
+ // "vol": "1",
+ // "done_avg_price": "16",
+ // "done_vol": "1",
+ // "way": 3,
+ // "category": 1,
+ // "open_type": 2,
+ // "make_fee": "0.00025",
+ // "take_fee": "0.012",
+ // "origin": "",
+ // "created_at": "2018-07-23T11:55:56.715305Z",
+ // "finished_at": "2018-07-23T11:55:56.763941Z",
+ // "status": 4,
+ // "errno": 0
+ // }
+ //
+ let id = undefined;
+ if (typeof order === 'string') {
+ id = order;
+ order = {};
+ }
+ id = this.safeString (order, 'order_id', id);
+ let timestamp = this.parse8601 (this.safeString (order, 'created_at'));
+ timestamp = this.safeInteger (order, 'create_time', timestamp);
+ const marketId = this.safeString2 (order, 'symbol', 'contract_id');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ let status = undefined;
+ if (market !== undefined) {
+ status = this.parseOrderStatusByType (market['type'], this.safeString (order, 'status'));
+ }
+ let price = this.safeFloat (order, 'price');
+ let average = this.safeFloat2 (order, 'price_avg', 'done_avg_price');
+ const amount = this.safeFloat2 (order, 'size', 'vol');
+ let cost = undefined;
+ let filled = this.safeFloat2 (order, 'filled_size', 'done_vol');
+ let remaining = undefined;
+ if (amount !== undefined) {
+ if (remaining !== undefined) {
+ if (filled === undefined) {
+ filled = Math.max (0, amount - remaining);
+ }
+ }
+ if (filled !== undefined) {
+ if (remaining === undefined) {
+ remaining = Math.max (0, amount - filled);
+ }
+ if (cost === undefined) {
+ if (average !== undefined) {
+ cost = average * filled;
+ }
+ }
+ }
+ }
+ let side = this.safeString (order, 'side');
+ // 1 = Open long
+ // 2 = Close short
+ // 3 = Close long
+ // 4 = Open short
+ side = this.safeString (order, 'way', side);
+ const category = this.safeInteger (order, 'category');
+ let type = this.safeString (order, 'type');
+ if (category === 1) {
+ type = 'limit';
+ } else if (category === 2) {
+ type = 'market';
+ }
+ if (type === 'market') {
+ if (price === 0.0) {
+ price = undefined;
+ }
+ if (average === 0.0) {
+ average = undefined;
+ }
+ }
+ return {
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'info': order,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': undefined,
+ 'trades': undefined,
+ };
+ }
+
+ parseOrderStatusByType (type, status) {
+ const statusesByType = {
+ 'spot': {
+ '1': 'failed', // Order failure
+ '2': 'open', // Placing order
+ '3': 'failed', // Order failure, Freeze failure
+ '4': 'open', // Order success, Pending for fulfilment
+ '5': 'open', // Partially filled
+ '6': 'closed', // Fully filled
+ '7': 'canceling', // Canceling
+ '8': 'canceled', // Canceled
+ },
+ 'swap': {
+ '1': 'open', // Submitting
+ '2': 'open', // Commissioned
+ '4': 'closed', // Completed
+ },
+ };
+ const statuses = this.safeValue (statusesByType, type, {});
+ return this.safeString (statuses, status, status);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {};
+ let method = undefined;
+ if (market['spot']) {
+ request['symbol'] = market['id'];
+ request['side'] = side;
+ request['type'] = type;
+ method = 'privateSpotPostSubmitOrder';
+ if (type === 'limit') {
+ request['size'] = this.amountToPrecision (symbol, amount);
+ request['price'] = this.priceToPrecision (symbol, price);
+ } else if (type === 'market') {
+ // for market buy it requires the amount of quote currency to spend
+ if (side === 'buy') {
+ let notional = this.safeFloat (params, 'notional');
+ const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true);
+ if (createMarketBuyOrderRequiresPrice) {
+ if (price !== undefined) {
+ if (notional === undefined) {
+ notional = amount * price;
+ }
+ } else if (notional === undefined) {
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument or in the 'notional' extra parameter (the exchange-specific behaviour)");
+ }
+ } else {
+ notional = (notional === undefined) ? amount : notional;
+ }
+ const precision = market['precision']['price'];
+ request['notional'] = this.decimalToPrecision (notional, TRUNCATE, precision, this.precisionMode);
+ } else if (side === 'sell') {
+ request['size'] = this.amountToPrecision (symbol, amount);
+ }
+ }
+ } else if (market['swap'] || market['future']) {
+ method = 'privateContractPostSubmitOrder';
+ request['contractID'] = market['id'];
+ if (type === 'limit') {
+ request['category'] = 1;
+ } else if (type === 'market') {
+ request['category'] = 2;
+ }
+ request['way'] = side; // 1 = open long, 2 = close short, 3 = close long, 4 = open short
+ request['custom_id'] = this.nonce ();
+ request['open_type'] = 1; // 1 = cross margin, 2 = fixed margin
+ request['leverage'] = 1; // must meet the effective range of leverage configured in the contract
+ request['price'] = this.priceToPrecision (symbol, price);
+ request['vol'] = this.amountToPrecision (symbol, amount);
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot and contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "order_id": 2707217580
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {};
+ let method = undefined;
+ if (market['spot']) {
+ method = 'privateSpotPostCancelOrder';
+ request['order_id'] = parseInt (id);
+ request['symbol'] = market['id'];
+ } else if (market['swap'] || market['future']) {
+ method = 'privateContractPostCancelOrders';
+ request['contractID'] = market['id'];
+ request['orders'] = [ parseInt (id) ];
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "result": true
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "succeed": [
+ // 2707219612
+ // ],
+ // "failed": []
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const succeeded = this.safeValue (data, 'succeed');
+ if (succeeded !== undefined) {
+ id = this.safeString (succeeded, 0);
+ if (id === undefined) {
+ throw new InvalidOrder (this.id + ' cancelOrder failed to cancel ' + symbol + ' order id ' + id);
+ }
+ } else {
+ const result = this.safeValue (data, 'result');
+ if (!result) {
+ throw new InvalidOrder (this.id + ' cancelOrder ' + symbol + ' order id ' + id + ' is filled or canceled');
+ }
+ }
+ const order = this.parseOrder (id, market);
+ return this.extend (order, { 'id': id });
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelAllOrders requires a symbol argument');
+ }
+ const side = this.safeString (params, 'side');
+ if (side === undefined) {
+ throw new ArgumentsRequired (this.id + " cancelAllOrders requires a `side` parameter ('buy' or 'sell')");
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ if (!market['spot']) {
+ throw new NotSupported (this.id + ' cancelAllOrders does not support ' + market['type'] + ' orders, only spot orders are accepted');
+ }
+ const request = {
+ 'symbol': market['id'],
+ 'side': side, // 'buy' or 'sell'
+ };
+ const response = await this.privateSpotPostCancelOrders (this.extend (request, params));
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {}
+ // }
+ //
+ return response;
+ }
+
+ async cancelOrders (ids, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' canelOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ if (!market['spot']) {
+ throw new NotSupported (this.id + ' cancelOrders does not support ' + market['type'] + ' orders, only contract orders are accepted');
+ }
+ const orders = [];
+ for (let i = 0; i < ids.length; i++) {
+ orders.push (parseInt (ids[i]));
+ }
+ const request = {
+ 'orders': orders,
+ };
+ const response = await this.privateContractPostCancelOrders (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "result": true
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "succeed": [
+ // 2707219612
+ // ],
+ // "failed": []
+ // }
+ // }
+ //
+ return response;
+ }
+
+ async fetchOrdersByStatus (status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrdersByStatus requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {};
+ let method = undefined;
+ if (market['spot']) {
+ method = 'privateSpotGetOrders';
+ request['symbol'] = market['id'];
+ request['offset'] = 1; // max offset * limit < 500
+ request['limit'] = 100; // max limit is 100
+ // 1 = Order failure
+ // 2 = Placing order
+ // 3 = Order failure, Freeze failure
+ // 4 = Order success, Pending for fulfilment
+ // 5 = Partially filled
+ // 6 = Fully filled
+ // 7 = Canceling
+ // 8 = Canceled
+ // 9 = Outstanding (4 and 5)
+ // 10 = 6 and 8
+ if (status === 'open') {
+ request['status'] = 9;
+ } else if (status === 'closed') {
+ request['status'] = 6;
+ } else {
+ request['status'] = status;
+ }
+ } else if (market['swap'] || market['future']) {
+ method = 'privateContractGetUserOrders';
+ request['contractID'] = market['id'];
+ // request['offset'] = 1;
+ if (limit !== undefined) {
+ request['size'] = limit; // max 60
+ }
+ // 0 = All
+ // 1 = Submitting
+ // 2 = Commissioned
+ // 3 = 1 and 2
+ // 4 = Completed
+ if (status === 'open') {
+ request['status'] = 3;
+ } else if (status === 'closed') {
+ request['status'] = 4;
+ } else {
+ request['status'] = status;
+ }
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"70e7d427-7436-4fb8-8cdd-97e1f5eadbe9",
+ // "data":{
+ // "current_page":1,
+ // "orders":[
+ // {
+ // "order_id":2147601241,
+ // "symbol":"BTC_USDT",
+ // "create_time":1591099963000,
+ // "side":"sell",
+ // "type":"limit",
+ // "price":"9000.00",
+ // "price_avg":"0.00",
+ // "size":"1.00000",
+ // "notional":"9000.00000000",
+ // "filled_notional":"0.00000000",
+ // "filled_size":"0.00000",
+ // "status":"4"
+ // }
+ // ]
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "orders": [
+ // {
+ // "order_id": 10284160,
+ // "contract_id": 1,
+ // "price": "8",
+ // "vol": "4",
+ // "done_avg_price": "0",
+ // "done_vol": "0",
+ // "way": 1,
+ // "category": 1,
+ // "open_type": 2,
+ // "make_fee": "0",
+ // "take_fee": "0",
+ // "origin": "",
+ // "created_at": "2018-07-17T07:24:13.410507Z",
+ // "finished_at": null,
+ // "status": 2,
+ // "errno": 0
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const orders = this.safeValue (data, 'orders', []);
+ return this.parseOrders (orders, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchOrdersByStatus ('open', symbol, since, limit, params);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchOrdersByStatus ('closed', symbol, since, limit, params);
+ }
+
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ if (!(market['swap'] || market['future'])) {
+ throw new NotSupported (this.id + ' fetchOrders does not support ' + market['type'] + ' markets, only contracts are supported');
+ }
+ return await this.fetchOrdersByStatus (0, symbol, since, limit, params);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const request = {};
+ const market = this.market (symbol);
+ let method = undefined;
+ if (typeof id !== 'string') {
+ id = id.toString ();
+ }
+ if (market['spot']) {
+ request['symbol'] = market['id'];
+ request['order_id'] = id;
+ method = 'privateSpotGetOrderDetail';
+ } else if (market['swap'] || market['future']) {
+ request['contractID'] = market['id'];
+ request['orderID'] = id;
+ method = 'privateContractGetUserOrderInfo';
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // spot
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"a27c2cb5-ead4-471d-8455-1cfeda054ea6",
+ // "data": {
+ // "order_id":1736871726781,
+ // "symbol":"BTC_USDT",
+ // "create_time":1591096004000,
+ // "side":"sell",
+ // "type":"market",
+ // "price":"0.00",
+ // "price_avg":"0.00",
+ // "size":"0.02000",
+ // "notional":"0.00000000",
+ // "filled_notional":"0.00000000",
+ // "filled_size":"0.00000",
+ // "status":"8"
+ // }
+ // }
+ //
+ // contract
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "orders": [
+ // {
+ // "order_id": 10539098,
+ // "contract_id": 1,
+ // "position_id": 10539088,
+ // "account_id": 10,
+ // "price": "16",
+ // "vol": "1",
+ // "done_avg_price": "16",
+ // "done_vol": "1",
+ // "way": 3,
+ // "category": 1,
+ // "make_fee": "0.00025",
+ // "take_fee": "0.012",
+ // "origin": "",
+ // "created_at": "2018-07-23T11:55:56.715305Z",
+ // "finished_at": "2018-07-23T11:55:56.763941Z",
+ // "status": 4,
+ // "errno": 0
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ if ('orders' in data) {
+ const orders = this.safeValue (data, 'orders', []);
+ const firstOrder = this.safeValue (orders, 0);
+ if (firstOrder === undefined) {
+ throw new OrderNotFound (this.id + ' fetchOrder could not find ' + symbol + ' order id ' + id);
+ }
+ return this.parseOrder (firstOrder, market);
+ } else {
+ return this.parseOrder (data, market);
+ }
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privateAccountGetDepositAddress (this.extend (request, params));
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"0e6edd79-f77f-4251-abe5-83ba75d06c1a",
+ // "data":{
+ // "currency":"USDT-TRC20",
+ // "chain":"USDT-TRC20",
+ // "address":"TGR3ghy2b5VLbyAYrmiE15jasR6aPHTvC5",
+ // "address_memo":""
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const address = this.safeString (data, 'address');
+ const tag = this.safeString (data, 'address_memo');
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': response,
+ };
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ 'amount': amount,
+ 'destination': 'To Digital Address', // To Digital Address, To Binance, To OKEX
+ 'address': address,
+ };
+ if (tag !== undefined) {
+ request['address_memo'] = tag;
+ }
+ const response = await this.privateAccountPostWithdrawApply (this.extend (request, params));
+ //
+ // {
+ // "code": 1000,
+ // "trace":"886fb6ae-456b-4654-b4e0-d681ac05cea1",
+ // "message": "OK",
+ // "data": {
+ // "withdraw_id": "121212"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data');
+ const transaction = this.parseTransaction (data, currency);
+ return this.extend (transaction, {
+ 'code': code,
+ 'address': address,
+ 'tag': tag,
+ });
+ }
+
+ async fetchTransactionsByType (type, code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ if (limit === undefined) {
+ limit = 50; // max 50
+ }
+ const request = {
+ 'operation_type': type, // deposit or withdraw
+ 'offset': 1,
+ 'limit': limit,
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currenc (code);
+ request['currency'] = currency['id'];
+ }
+ const response = await this.privateAccountGetDepositWithdrawHistory (this.extend (request, params));
+ //
+ // {
+ // "message":"OK",
+ // "code":1000,
+ // "trace":"142bf92a-fc50-4689-92b6-590886f90b97",
+ // "data":{
+ // "records":[
+ // {
+ // "withdraw_id":"1679952",
+ // "deposit_id":"",
+ // "operation_type":"withdraw",
+ // "currency":"BMX",
+ // "apply_time":1588867374000,
+ // "arrival_amount":"59.000000000000",
+ // "fee":"1.000000000000",
+ // "status":0,
+ // "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
+ // "address_memo":"",
+ // "tx_id":""
+ // },
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const records = this.safeValue (data, 'records', []);
+ return this.parseTransactions (records, currency, since, limit);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsByType ('deposit', code, since, limit, params);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsByType ('withdraw', code, since, limit, params);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ '0': 'pending', // Create
+ '1': 'pending', // Submitted, waiting for withdrawal
+ '2': 'pending', // Processing
+ '3': 'ok', // Success
+ '4': 'canceled', // Cancel
+ '5': 'failed', // Fail
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // withdraw
+ //
+ // {
+ // "withdraw_id": "121212"
+ // }
+ //
+ // fetchDeposits, fetchWithdrawals
+ //
+ // {
+ // "withdraw_id":"1679952",
+ // "deposit_id":"",
+ // "operation_type":"withdraw",
+ // "currency":"BMX",
+ // "apply_time":1588867374000,
+ // "arrival_amount":"59.000000000000",
+ // "fee":"1.000000000000",
+ // "status":0,
+ // "address":"0xe57b69a8776b37860407965B73cdFFBDFe668Bb5",
+ // "address_memo":"",
+ // "tx_id":""
+ // }
+ //
+ let id = undefined;
+ const withdrawId = this.safeString (transaction, 'withdraw_id');
+ const depositId = this.safeString (transaction, 'deposit_id');
+ let type = undefined;
+ if ((withdrawId !== undefined) && (withdrawId !== '')) {
+ type = 'withdraw';
+ id = withdrawId;
+ } else if ((depositId !== undefined) && (depositId !== '')) {
+ type = 'deposit';
+ id = depositId;
+ }
+ const amount = this.safeFloat (transaction, 'arrival_amount');
+ const timestamp = this.safeInteger (transaction, 'tapply_timeime');
+ const currencyId = this.safeString (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const feeCost = this.safeFloat (transaction, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': code,
+ };
+ }
+ let txid = this.safeString (transaction, 'tx_id');
+ if (txid === '') {
+ txid = undefined;
+ }
+ const address = this.safeString (transaction, 'address');
+ const tag = this.safeString (transaction, 'address_memo');
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': code,
+ 'amount': amount,
+ 'address': address,
+ 'addressFrom': undefined,
+ 'addressTo': undefined,
+ 'tag': tag,
+ 'tagFrom': undefined,
+ 'tagTo': undefined,
+ 'status': status,
+ 'type': type,
+ 'updated': undefined,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': fee,
+ };
+ }
+
+ nonce () {
+ return this.milliseconds ();
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const baseUrl = this.implodeParams (this.urls['api'], { 'hostname': this.hostname });
+ const access = this.safeString (api, 0);
+ const type = this.safeString (api, 1);
+ let url = baseUrl + '/' + type;
+ if (type !== 'system') {
+ url += '/' + this.version;
+ }
+ if (type === 'contract') {
+ url += '/' + 'ifcontract';
+ }
+ url += '/' + this.implodeParams (path, params);
+ const query = this.omit (params, this.extractParams (path));
+ if (type === 'system') {
+ if (Object.keys (query).length) {
+ // console.log (query);
+ url += '?' + this.urlencode (query);
+ }
+ } else if (access === 'public') {
+ if (Object.keys (query).length) {
+ // console.log (query);
+ url += '?' + this.urlencode (query);
+ }
+ } else if (access === 'private') {
+ this.checkRequiredCredentials ();
+ const timestamp = this.milliseconds ().toString ();
+ let queryString = '';
+ headers = {
+ 'X-BM-KEY': this.apiKey,
+ 'X-BM-TIMESTAMP': timestamp,
+ };
+ if ((method === 'POST') || (method === 'PUT')) {
+ headers['Content-Type'] = 'application/json';
+ body = this.json (query);
+ queryString = body;
+ } else {
+ if (Object.keys (query).length) {
+ queryString = this.urlencode (query);
+ url += '?' + queryString;
+ }
+ }
+ const auth = timestamp + '#' + this.uid + '#' + queryString;
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret));
+ headers['X-BM-SIGN'] = signature;
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return;
+ }
+ //
+ // spot
+ //
+ // {"message":"Bad Request [to is empty]","code":50000,"trace":"f9d46e1b-4edb-4d07-a06e-4895fb2fc8fc","data":{}}
+ // {"message":"Bad Request [from is empty]","code":50000,"trace":"579986f7-c93a-4559-926b-06ba9fa79d76","data":{}}
+ // {"message":"Kline size over 500","code":50004,"trace":"d625caa8-e8ca-4bd2-b77c-958776965819","data":{}}
+ // {"message":"Balance not enough","code":50020,"trace":"7c709d6a-3292-462c-98c5-32362540aeef","data":{}}
+ //
+ // contract
+ //
+ // {"errno":"OK","message":"INVALID_PARAMETER","code":49998,"trace":"eb5ebb54-23cd-4de2-9064-e090b6c3b2e3","data":null}
+ //
+ const message = this.safeString (response, 'message');
+ const errorCode = this.safeString (response, 'code');
+ if (((errorCode !== undefined) && (errorCode !== '1000')) || ((message !== undefined) && (message !== 'OK'))) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], errorCode, feedback);
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitmax.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitmax.js
new file mode 100644
index 000000000..0fa940d42
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitmax.js
@@ -0,0 +1,1725 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ArgumentsRequired, AuthenticationError, ExchangeError, InsufficientFunds, InvalidOrder, BadSymbol, PermissionDenied, BadRequest } = require ('./base/errors');
+const { ROUND, TICK_SIZE } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class bitmax extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'bitmax',
+ 'name': 'BitMax',
+ 'countries': [ 'CN' ], // China
+ 'rateLimit': 500,
+ // new metainfo interface
+ 'has': {
+ 'CORS': false,
+ 'fetchMarkets': true,
+ 'fetchCurrencies': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchOHLCV': true,
+ 'fetchTrades': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
+ 'createOrder': true,
+ 'cancelOrder': true,
+ 'cancelAllOrders': true,
+ 'fetchDepositAddress': true,
+ 'fetchTransactions': true,
+ 'fetchDeposits': true,
+ 'fetchWithdrawals': true,
+ 'fetchOrder': true,
+ 'fetchOrders': true,
+ 'fetchOpenOrders': true,
+ 'fetchClosedOrders': true,
+ },
+ 'timeframes': {
+ '1m': '1',
+ '5m': '5',
+ '15m': '15',
+ '30m': '30',
+ '1h': '60',
+ '2h': '120',
+ '4h': '240',
+ '6h': '360',
+ '12h': '720',
+ '1d': '1d',
+ '1w': '1w',
+ '1M': '1m',
+ },
+ 'version': 'v1',
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/66820319-19710880-ef49-11e9-8fbe-16be62a11992.jpg',
+ 'api': 'https://bitmax.io',
+ 'test': 'https://bitmax-test.io',
+ 'www': 'https://bitmax.io',
+ 'doc': [
+ 'https://bitmax-exchange.github.io/bitmax-pro-api/#bitmax-pro-api-documentation',
+ ],
+ 'fees': 'https://bitmax.io/#/feeRate/tradeRate',
+ 'referral': 'https://bitmax.io/#/register?inviteCode=EL6BXBQM',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'assets',
+ 'products',
+ 'ticker',
+ 'barhist/info',
+ 'barhist',
+ 'depth',
+ 'trades',
+ 'cash/assets', // not documented
+ 'cash/products', // not documented
+ 'margin/assets', // not documented
+ 'margin/products', // not documented
+ 'futures/collateral',
+ 'futures/contracts',
+ 'futures/ref-px',
+ 'futures/market-data',
+ 'futures/funding-rates',
+ ],
+ },
+ 'accountCategory': {
+ 'get': [
+ 'balance',
+ 'order/open',
+ 'order/status',
+ 'order/hist/current',
+ 'risk',
+ ],
+ 'post': [
+ 'order',
+ 'order/batch',
+ ],
+ 'delete': [
+ 'order',
+ 'order/all',
+ 'order/batch',
+ ],
+ },
+ 'accountGroup': {
+ 'get': [
+ 'cash/balance',
+ 'margin/balance',
+ 'margin/risk',
+ 'transfer',
+ 'futures/collateral-balance',
+ 'futures/position',
+ 'futures/risk',
+ 'futures/funding-payments',
+ 'order/hist',
+ ],
+ 'post': [
+ 'futures/transfer/deposit',
+ 'futures/transfer/withdraw',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'info',
+ 'wallet/transactions',
+ 'wallet/deposit/address', // not documented
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.001,
+ 'maker': 0.001,
+ },
+ },
+ 'precisionMode': TICK_SIZE,
+ 'options': {
+ 'account-category': 'cash', // 'cash'/'margin'/'futures'
+ 'account-group': undefined,
+ 'fetchClosedOrders': {
+ 'method': 'accountGroupGetOrderHist', // 'accountGroupGetAccountCategoryOrderHistCurrent'
+ },
+ },
+ 'exceptions': {
+ 'exact': {
+ // not documented
+ '1900': BadRequest, // {"code":1900,"message":"Invalid Http Request Input"}
+ '2100': AuthenticationError, // {"code":2100,"message":"ApiKeyFailure"}
+ '5002': BadSymbol, // {"code":5002,"message":"Invalid Symbol"}
+ '6001': BadSymbol, // {"code":6001,"message":"Trading is disabled on symbol."}
+ '6010': InsufficientFunds, // {'code': 6010, 'message': 'Not enough balance.'}
+ '60060': InvalidOrder, // { 'code': 60060, 'message': 'The order is already filled or canceled.' }
+ '600503': InvalidOrder, // {"code":600503,"message":"Notional is too small."}
+ // documented
+ '100001': BadRequest, // INVALID_HTTP_INPUT Http request is invalid
+ '100002': BadRequest, // DATA_NOT_AVAILABLE Some required data is missing
+ '100003': BadRequest, // KEY_CONFLICT The same key exists already
+ '100004': BadRequest, // INVALID_REQUEST_DATA The HTTP request contains invalid field or argument
+ '100005': BadRequest, // INVALID_WS_REQUEST_DATA Websocket request contains invalid field or argument
+ '100006': BadRequest, // INVALID_ARGUMENT The arugment is invalid
+ '100007': BadRequest, // ENCRYPTION_ERROR Something wrong with data encryption
+ '100008': BadSymbol, // SYMBOL_ERROR Symbol does not exist or not valid for the request
+ '100009': AuthenticationError, // AUTHORIZATION_NEEDED Authorization is require for the API access or request
+ '100010': BadRequest, // INVALID_OPERATION The action is invalid or not allowed for the account
+ '100011': BadRequest, // INVALID_TIMESTAMP Not a valid timestamp
+ '100012': BadRequest, // INVALID_STR_FORMAT String format does not
+ '100013': BadRequest, // INVALID_NUM_FORMAT Invalid number input
+ '100101': ExchangeError, // UNKNOWN_ERROR Some unknown error
+ '150001': BadRequest, // INVALID_JSON_FORMAT Require a valid json object
+ '200001': AuthenticationError, // AUTHENTICATION_FAILED Authorization failed
+ '200002': ExchangeError, // TOO_MANY_ATTEMPTS Tried and failed too many times
+ '200003': ExchangeError, // ACCOUNT_NOT_FOUND Account not exist
+ '200004': ExchangeError, // ACCOUNT_NOT_SETUP Account not setup properly
+ '200005': ExchangeError, // ACCOUNT_ALREADY_EXIST Account already exist
+ '200006': ExchangeError, // ACCOUNT_ERROR Some error related with error
+ '200007': ExchangeError, // CODE_NOT_FOUND
+ '200008': ExchangeError, // CODE_EXPIRED Code expired
+ '200009': ExchangeError, // CODE_MISMATCH Code does not match
+ '200010': AuthenticationError, // PASSWORD_ERROR Wrong assword
+ '200011': ExchangeError, // CODE_GEN_FAILED Do not generate required code promptly
+ '200012': ExchangeError, // FAKE_COKE_VERIFY
+ '200013': ExchangeError, // SECURITY_ALERT Provide security alert message
+ '200014': PermissionDenied, // RESTRICTED_ACCOUNT Account is restricted for certain activity, such as trading, or withdraw.
+ '200015': PermissionDenied, // PERMISSION_DENIED No enough permission for the operation
+ '300001': InvalidOrder, // INVALID_PRICE Order price is invalid
+ '300002': InvalidOrder, // INVALID_QTY Order size is invalid
+ '300003': InvalidOrder, // INVALID_SIDE Order side is invalid
+ '300004': InvalidOrder, // INVALID_NOTIONAL Notional is too small or too large
+ '300005': InvalidOrder, // INVALID_TYPE Order typs is invalid
+ '300006': InvalidOrder, // INVALID_ORDER_ID Order id is invalid
+ '300007': InvalidOrder, // INVALID_TIME_IN_FORCE Time In Force in order request is invalid
+ '300008': InvalidOrder, // INVALID_ORDER_PARAMETER Some order parameter is invalid
+ '300009': InvalidOrder, // TRADING_VIOLATION Trading violation on account or asset
+ '300011': InsufficientFunds, // INVALID_BALANCE No enough account or asset balance for the trading
+ '300012': BadSymbol, // INVALID_PRODUCT Not a valid product supported by exchange
+ '300013': InvalidOrder, // INVALID_BATCH_ORDER Some or all orders are invalid in batch order request
+ '300020': InvalidOrder, // TRADING_RESTRICTED There is some trading restriction on account or asset
+ '300021': InvalidOrder, // TRADING_DISABLED Trading is disabled on account or asset
+ '300031': InvalidOrder, // NO_MARKET_PRICE No market price for market type order trading
+ '310001': InsufficientFunds, // INVALID_MARGIN_BALANCE No enough margin balance
+ '310002': InvalidOrder, // INVALID_MARGIN_ACCOUNT Not a valid account for margin trading
+ '310003': InvalidOrder, // MARGIN_TOO_RISKY Leverage is too high
+ '310004': BadSymbol, // INVALID_MARGIN_ASSET This asset does not support margin trading
+ '310005': InvalidOrder, // INVALID_REFERENCE_PRICE There is no valid reference price
+ '510001': ExchangeError, // SERVER_ERROR Something wrong with server.
+ '900001': ExchangeError, // HUMAN_CHALLENGE Human change do not pass
+ },
+ 'broad': {},
+ },
+ 'commonCurrencies': {
+ 'BTCBEAR': 'BEAR',
+ 'BTCBULL': 'BULL',
+ },
+ });
+ }
+
+ getAccount (params = {}) {
+ // get current or provided bitmax sub-account
+ const account = this.safeValue (params, 'account', this.options['account']);
+ return account.toLowerCase ().capitalize ();
+ }
+
+ async fetchCurrencies (params = {}) {
+ const assets = await this.publicGetAssets (params);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "assetCode" : "LTCBULL",
+ // "assetName" : "3X Long LTC Token",
+ // "precisionScale" : 9,
+ // "nativeScale" : 4,
+ // "withdrawalFee" : "0.2",
+ // "minWithdrawalAmt" : "1.0",
+ // "status" : "Normal"
+ // },
+ // ]
+ // }
+ //
+ const margin = await this.publicGetMarginAssets (params);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "assetCode":"BTT",
+ // "borrowAssetCode":"BTT-B",
+ // "interestAssetCode":"BTT-I",
+ // "nativeScale":0,
+ // "numConfirmations":1,
+ // "withdrawFee":"100.0",
+ // "minWithdrawalAmt":"1000.0",
+ // "statusCode":"Normal",
+ // "statusMessage":"",
+ // "interestRate":"0.001"
+ // }
+ // ]
+ // }
+ //
+ const cash = await this.publicGetCashAssets (params);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "assetCode":"LTCBULL",
+ // "nativeScale":4,
+ // "numConfirmations":20,
+ // "withdrawFee":"0.2",
+ // "minWithdrawalAmt":"1.0",
+ // "statusCode":"Normal",
+ // "statusMessage":""
+ // }
+ // ]
+ // }
+ //
+ const assetsData = this.safeValue (assets, 'data', []);
+ const marginData = this.safeValue (margin, 'data', []);
+ const cashData = this.safeValue (cash, 'data', []);
+ const assetsById = this.indexBy (assetsData, 'assetCode');
+ const marginById = this.indexBy (marginData, 'assetCode');
+ const cashById = this.indexBy (cashData, 'assetCode');
+ const dataById = this.deepExtend (assetsById, marginById, cashById);
+ const ids = Object.keys (dataById);
+ const result = {};
+ for (let i = 0; i < ids.length; i++) {
+ const id = ids[i];
+ const currency = dataById[id];
+ const code = this.safeCurrencyCode (id);
+ const precision = this.safeInteger2 (currency, 'precisionScale', 'nativeScale');
+ // why would the exchange API have different names for the same field
+ const fee = this.safeFloat2 (currency, 'withdrawFee', 'withdrawalFee');
+ const status = this.safeString2 (currency, 'status', 'statusCode');
+ const active = (status === 'Normal');
+ const margin = ('borrowAssetCode' in currency);
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': currency,
+ 'type': undefined,
+ 'margin': margin,
+ 'name': this.safeString (currency, 'assetName'),
+ 'active': active,
+ 'fee': fee,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': Math.pow (10, -precision),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': Math.pow (10, -precision),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (currency, 'minWithdrawalAmt'),
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchMarkets (params = {}) {
+ const products = await this.publicGetProducts (params);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "symbol":"LBA/BTC",
+ // "baseAsset":"LBA",
+ // "quoteAsset":"BTC",
+ // "status":"Normal",
+ // "minNotional":"0.000625",
+ // "maxNotional":"6.25",
+ // "marginTradable":false,
+ // "commissionType":"Quote",
+ // "commissionReserveRate":"0.001",
+ // "tickSize":"0.000000001",
+ // "lotSize":"1"
+ // },
+ // ]
+ // }
+ //
+ const cash = await this.publicGetCashProducts (params);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "symbol":"QTUM/BTC",
+ // "domain":"BTC",
+ // "tradingStartTime":1569506400000,
+ // "collapseDecimals":"0.0001,0.000001,0.00000001",
+ // "minQty":"0.000000001",
+ // "maxQty":"1000000000",
+ // "minNotional":"0.000625",
+ // "maxNotional":"12.5",
+ // "statusCode":"Normal",
+ // "statusMessage":"",
+ // "tickSize":"0.00000001",
+ // "useTick":false,
+ // "lotSize":"0.1",
+ // "useLot":false,
+ // "commissionType":"Quote",
+ // "commissionReserveRate":"0.001",
+ // "qtyScale":1,
+ // "priceScale":8,
+ // "notionalScale":4
+ // }
+ // ]
+ // }
+ //
+ const futures = await this.publicGetFuturesContracts (params);
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "symbol":"BTC-PERP",
+ // "tradingStartTime":1579701600000,
+ // "collapseDecimals":"1,0.1,0.01",
+ // "minQty":"0.000000001",
+ // "maxQty":"1000000000",
+ // "minNotional":"5",
+ // "maxNotional":"1000000",
+ // "statusCode":"Normal",
+ // "statusMessage":"",
+ // "tickSize":"0.25",
+ // "lotSize":"0.0001",
+ // "priceScale":2,
+ // "qtyScale":4,
+ // "notionalScale":2
+ // }
+ // ]
+ // }
+ //
+ const productsData = this.safeValue (products, 'data', []);
+ const productsById = this.indexBy (productsData, 'symbol');
+ const cashData = this.safeValue (cash, 'data', []);
+ const futuresData = this.safeValue (futures, 'data', []);
+ const cashAndFuturesData = this.arrayConcat (cashData, futuresData);
+ const cashAndFuturesById = this.indexBy (cashAndFuturesData, 'symbol');
+ const dataById = this.deepExtend (productsById, cashAndFuturesById);
+ const ids = Object.keys (dataById);
+ const result = [];
+ for (let i = 0; i < ids.length; i++) {
+ const id = ids[i];
+ const market = dataById[id];
+ const baseId = this.safeString (market, 'baseAsset');
+ const quoteId = this.safeString (market, 'quoteAsset');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const precision = {
+ 'amount': this.safeFloat (market, 'lotSize'),
+ 'price': this.safeFloat (market, 'tickSize'),
+ };
+ const status = this.safeString (market, 'status');
+ const active = (status === 'Normal');
+ const type = ('useLot' in market) ? 'spot' : 'future';
+ const spot = (type === 'spot');
+ const future = (type === 'future');
+ let symbol = id;
+ if (!future) {
+ symbol = base + '/' + quote;
+ }
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'info': market,
+ 'type': type,
+ 'spot': spot,
+ 'future': future,
+ 'active': active,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': this.safeFloat (market, 'minQty'),
+ 'max': this.safeFloat (market, 'maxQty'),
+ },
+ 'price': {
+ 'min': this.safeFloat (market, 'tickSize'),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': this.safeFloat (market, 'minNotional'),
+ 'max': this.safeFloat (market, 'maxNotional'),
+ },
+ },
+ });
+ }
+ return result;
+ }
+
+ calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) {
+ // TODO: fee calculation here is incorrect, we need to support tiered fee calculation.
+ const market = this.markets[symbol];
+ let key = 'quote';
+ const rate = market[takerOrMaker];
+ let cost = amount * rate;
+ let precision = market['precision']['price'];
+ if (side === 'sell') {
+ cost *= price;
+ } else {
+ key = 'base';
+ precision = market['precision']['amount'];
+ }
+ cost = this.decimalToPrecision (cost, ROUND, precision, this.precisionMode);
+ return {
+ 'type': takerOrMaker,
+ 'currency': market[key],
+ 'rate': rate,
+ 'cost': parseFloat (cost),
+ };
+ }
+
+ async fetchAccounts (params = {}) {
+ let accountGroup = this.safeString (this.options, 'account-group');
+ let response = undefined;
+ if (accountGroup === undefined) {
+ response = await this.privateGetInfo (params);
+ //
+ // {
+ // "code":0,
+ // "data":{
+ // "email":"igor.kroitor@gmail.com",
+ // "accountGroup":8,
+ // "viewPermission":true,
+ // "tradePermission":true,
+ // "transferPermission":true,
+ // "cashAccount":["cshrHKLZCjlZ2ejqkmvIHHtPmLYqdnda"],
+ // "marginAccount":["martXoh1v1N3EMQC5FDtSj5VHso8aI2Z"],
+ // "futuresAccount":["futc9r7UmFJAyBY2rE3beA2JFxav2XFF"],
+ // "userUID":"U6491137460"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ accountGroup = this.safeString (data, 'accountGroup');
+ this.options['account-group'] = accountGroup;
+ }
+ return [
+ {
+ 'id': accountGroup,
+ 'type': undefined,
+ 'currency': undefined,
+ 'info': response,
+ },
+ ];
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'fetchBalance', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeString (account, 'id');
+ const request = {
+ 'account-group': accountGroup,
+ };
+ let method = 'accountCategoryGetBalance';
+ if (accountCategory === 'futures') {
+ method = 'accountGroupGetFuturesCollateralBalance';
+ } else {
+ request['account-category'] = accountCategory;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // cash
+ //
+ // {
+ // 'code': 0,
+ // 'data': [
+ // {
+ // 'asset': 'BCHSV',
+ // 'totalBalance': '64.298000048',
+ // 'availableBalance': '64.298000048',
+ // },
+ // ]
+ // }
+ //
+ // margin
+ //
+ // {
+ // 'code': 0,
+ // 'data': [
+ // {
+ // 'asset': 'BCHSV',
+ // 'totalBalance': '64.298000048',
+ // 'availableBalance': '64.298000048',
+ // 'borrowed': '0',
+ // 'interest': '0',
+ // },
+ // ]
+ // }
+ //
+ // futures
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {"asset":"BTC","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"9456.59"},
+ // {"asset":"ETH","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"235.95"},
+ // {"asset":"USDT","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"1"},
+ // {"asset":"USDC","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"1.00035"},
+ // {"asset":"PAX","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"1.00045"},
+ // {"asset":"USDTR","totalBalance":"0","availableBalance":"0","maxTransferrable":"0","priceInUSDT":"1"}
+ // ]
+ // }
+ //
+ const result = { 'info': response };
+ 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, 'asset'));
+ const account = this.account ();
+ account['free'] = this.safeFloat (balance, 'availableBalance');
+ account['total'] = this.safeFloat (balance, 'totalBalance');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this.publicGetDepth (this.extend (request, params));
+ //
+ // {
+ // "code":0,
+ // "data":{
+ // "m":"depth-snapshot",
+ // "symbol":"BTC-PERP",
+ // "data":{
+ // "ts":1590223998202,
+ // "seqnum":115444921,
+ // "asks":[
+ // ["9207.5","18.2383"],
+ // ["9207.75","18.8235"],
+ // ["9208","10.7873"],
+ // ],
+ // "bids":[
+ // ["9207.25","0.4009"],
+ // ["9207","0.003"],
+ // ["9206.5","0.003"],
+ // ]
+ // }
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const orderbook = this.safeValue (data, 'data', {});
+ const timestamp = this.safeInteger (orderbook, 'ts');
+ const result = this.parseOrderBook (orderbook, timestamp);
+ result['nonce'] = this.safeInteger (orderbook, 'seqnum');
+ return result;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // {
+ // "symbol":"QTUM/BTC",
+ // "open":"0.00016537",
+ // "close":"0.00019077",
+ // "high":"0.000192",
+ // "low":"0.00016537",
+ // "volume":"846.6",
+ // "ask":["0.00018698","26.2"],
+ // "bid":["0.00018408","503.7"],
+ // "type":"spot"
+ // }
+ //
+ const timestamp = undefined;
+ const marketId = this.safeString (ticker, 'symbol');
+ let symbol = undefined;
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else if (marketId !== undefined) {
+ const type = this.safeString (ticker, 'type');
+ if (type === 'spot') {
+ const [ baseId, quoteId ] = marketId.split ('/');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ const close = this.safeFloat (ticker, 'close');
+ const bid = this.safeValue (ticker, 'bid', []);
+ const ask = this.safeValue (ticker, 'ask', []);
+ const open = this.safeFloat (ticker, 'open');
+ let change = undefined;
+ let percentage = undefined;
+ let average = undefined;
+ if ((open !== undefined) && (close !== undefined)) {
+ change = close - open;
+ if (open > 0) {
+ percentage = change / open * 100;
+ }
+ average = this.sum (open, close) / 2;
+ }
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': this.safeFloat (bid, 0),
+ 'bidVolume': this.safeFloat (bid, 1),
+ 'ask': this.safeFloat (ask, 0),
+ 'askVolume': this.safeFloat (ask, 1),
+ 'vwap': undefined,
+ 'open': open,
+ 'close': close,
+ 'last': close,
+ 'previousClose': undefined, // previous day close
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': this.safeFloat (ticker, 'volume'),
+ 'quoteVolume': undefined,
+ 'info': ticker,
+ };
+ }
+
+ parseTickers (rawTickers, symbols = undefined) {
+ const tickers = [];
+ for (let i = 0; i < rawTickers.length; i++) {
+ tickers.push (this.parseTicker (rawTickers[i]));
+ }
+ return this.filterByArray (tickers, 'symbol', symbols);
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this.publicGetTicker (this.extend (request, params));
+ //
+ // {
+ // "code":0,
+ // "data":{
+ // "symbol":"BTC-PERP", // or "BTC/USDT"
+ // "open":"9073",
+ // "close":"9185.75",
+ // "high":"9185.75",
+ // "low":"9185.75",
+ // "volume":"576.8334",
+ // "ask":["9185.75","15.5863"],
+ // "bid":["9185.5","0.003"],
+ // "type":"derivatives", // or "spot"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTicker (data, market);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ if (symbols !== undefined) {
+ const marketIds = this.marketIds (symbols);
+ request['symbol'] = marketIds.join (',');
+ }
+ const response = await this.publicGetTicker (this.extend (request, params));
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "symbol":"QTUM/BTC",
+ // "open":"0.00016537",
+ // "close":"0.00019077",
+ // "high":"0.000192",
+ // "low":"0.00016537",
+ // "volume":"846.6",
+ // "ask":["0.00018698","26.2"],
+ // "bid":["0.00018408","503.7"],
+ // "type":"spot"
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTickers (data, symbols);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "m":"bar",
+ // "s":"BTC/USDT",
+ // "data":{
+ // "i":"1",
+ // "ts":1590228000000,
+ // "o":"9139.59",
+ // "c":"9131.94",
+ // "h":"9139.99",
+ // "l":"9121.71",
+ // "v":"25.20648"
+ // }
+ // }
+ //
+ const data = this.safeValue (ohlcv, 'data', {});
+ return [
+ this.safeInteger (data, 'ts'),
+ this.safeFloat (data, 'o'),
+ this.safeFloat (data, 'h'),
+ this.safeFloat (data, 'l'),
+ this.safeFloat (data, 'c'),
+ this.safeFloat (data, 'v'),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ 'interval': this.timeframes[timeframe],
+ };
+ // if since and limit are not specified
+ // the exchange will return just 1 last candle by default
+ const duration = this.parseTimeframe (timeframe);
+ const options = this.safeValue (this.options, 'fetchOHLCV', {});
+ const defaultLimit = this.safeInteger (options, 'limit', 500);
+ if (since !== undefined) {
+ request['from'] = since;
+ if (limit === undefined) {
+ limit = defaultLimit;
+ } else {
+ limit = Math.min (limit, defaultLimit);
+ }
+ request['to'] = this.sum (since, limit * duration * 1000, 1);
+ } else if (limit !== undefined) {
+ request['n'] = limit; // max 500
+ }
+ const response = await this.publicGetBarhist (this.extend (request, params));
+ //
+ // {
+ // "code":0,
+ // "data":[
+ // {
+ // "m":"bar",
+ // "s":"BTC/USDT",
+ // "data":{
+ // "i":"1",
+ // "ts":1590228000000,
+ // "o":"9139.59",
+ // "c":"9131.94",
+ // "h":"9139.99",
+ // "l":"9121.71",
+ // "v":"25.20648"
+ // }
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades
+ //
+ // {
+ // "p":"9128.5", // price
+ // "q":"0.0030", // quantity
+ // "ts":1590229002385, // timestamp
+ // "bm":false, // if true, the buyer is the market maker, we only use this field to "define the side" of a public trade
+ // "seqnum":180143985289898554
+ // }
+ //
+ const timestamp = this.safeInteger (trade, 'ts');
+ const price = this.safeFloat2 (trade, 'price', 'p');
+ const amount = this.safeFloat (trade, 'q');
+ let cost = undefined;
+ if ((price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ const buyerIsMaker = this.safeValue (trade, 'bm', false);
+ const makerOrTaker = buyerIsMaker ? 'maker' : 'taker';
+ const side = buyerIsMaker ? 'buy' : 'sell';
+ let symbol = undefined;
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ return {
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'id': undefined,
+ 'order': undefined,
+ 'type': undefined,
+ 'takerOrMaker': makerOrTaker,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': undefined,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ if (limit !== undefined) {
+ request['n'] = limit; // max 100
+ }
+ const response = await this.publicGetTrades (this.extend (request, params));
+ //
+ // {
+ // "code":0,
+ // "data":{
+ // "m":"trades",
+ // "symbol":"BTC-PERP",
+ // "data":[
+ // {"p":"9128.5","q":"0.0030","ts":1590229002385,"bm":false,"seqnum":180143985289898554},
+ // {"p":"9129","q":"0.0030","ts":1590229002642,"bm":false,"seqnum":180143985289898587},
+ // {"p":"9129.5","q":"0.0030","ts":1590229021306,"bm":false,"seqnum":180143985289899043}
+ // ]
+ // }
+ // }
+ //
+ const records = this.safeValue (response, 'data', []);
+ const trades = this.safeValue (records, 'data', []);
+ return this.parseTrades (trades, market, since, limit);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'PendingNew': 'open',
+ 'New': 'open',
+ 'PartiallyFilled': 'open',
+ 'Filled': 'closed',
+ 'Canceled': 'canceled',
+ 'Rejected': 'rejected',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // "id": "16e607e2b83a8bXHbAwwoqDo55c166fa",
+ // "orderId": "16e85b4d9b9a8bXHbAwwoqDoc3d66830",
+ // "orderType": "Market",
+ // "symbol": "BTC/USDT",
+ // "timestamp": 1573576916201
+ // }
+ //
+ // fetchOrder, fetchOpenOrders, fetchClosedOrders
+ //
+ // {
+ // "symbol": "BTC/USDT",
+ // "price": "8131.22",
+ // "orderQty": "0.00082",
+ // "orderType": "Market",
+ // "avgPx": "7392.02",
+ // "cumFee": "0.005152238",
+ // "cumFilledQty": "0.00082",
+ // "errorCode": "",
+ // "feeAsset": "USDT",
+ // "lastExecTime": 1575953151764,
+ // "orderId": "a16eee20b6750866943712zWEDdAjt3",
+ // "seqNum": 2623469,
+ // "side": "Buy",
+ // "status": "Filled",
+ // "stopPrice": "",
+ // "execInst": "NULL_VAL"
+ // }
+ //
+ // {
+ // "ac": "FUTURES",
+ // "accountId": "testabcdefg",
+ // "avgPx": "0",
+ // "cumFee": "0",
+ // "cumQty": "0",
+ // "errorCode": "NULL_VAL",
+ // "execInst": "NULL_VAL",
+ // "feeAsset": "USDT",
+ // "lastExecTime": 1584072844085,
+ // "orderId": "r170d21956dd5450276356bbtcpKa74",
+ // "orderQty": "1.1499",
+ // "orderType": "Limit",
+ // "price": "4000",
+ // "sendingTime": 1584072841033,
+ // "seqNum": 24105338,
+ // "side": "Buy",
+ // "status": "Canceled",
+ // "stopPrice": "",
+ // "symbol": "BTC-PERP"
+ // },
+ //
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '/');
+ let timestamp = this.safeInteger2 (order, 'timestamp', 'sendingTime');
+ let lastTradeTimestamp = this.safeInteger (order, 'lastExecTime');
+ const price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'orderQty');
+ const average = this.safeFloat (order, 'avgPx');
+ const filled = this.safeFloat2 (order, 'cumFilledQty', 'cumQty');
+ let remaining = undefined;
+ if (filled !== undefined) {
+ if (filled === 0) {
+ timestamp = lastTradeTimestamp;
+ lastTradeTimestamp = undefined;
+ }
+ if (amount !== undefined) {
+ remaining = Math.max (0, amount - filled);
+ }
+ }
+ let cost = undefined;
+ if ((average !== undefined) && (filled !== undefined)) {
+ cost = average * filled;
+ }
+ const id = this.safeString (order, 'orderId');
+ let clientOrderId = this.safeString (order, 'id');
+ if (clientOrderId !== undefined) {
+ if (clientOrderId.length < 1) {
+ clientOrderId = undefined;
+ }
+ }
+ const type = this.safeStringLower (order, 'orderType');
+ const side = this.safeStringLower (order, 'side');
+ const feeCost = this.safeFloat (order, 'cumFee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (order, 'feeAsset');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ const stopPrice = this.safeFloat (order, 'stopPrice');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': stopPrice,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': undefined,
+ };
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const market = this.market (symbol);
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'createOrder', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'id');
+ const request = {
+ 'account-group': accountGroup,
+ 'account-category': accountCategory,
+ 'symbol': market['id'],
+ 'time': this.milliseconds (),
+ 'orderQty': this.amountToPrecision (symbol, amount),
+ 'orderType': type, // "limit", "market", "stop_market", "stop_limit"
+ 'side': side, // "buy" or "sell"
+ // 'orderPrice': this.priceToPrecision (symbol, price),
+ // 'stopPrice': this.priceToPrecision (symbol, stopPrice), // required for stop orders
+ // 'postOnly': 'false', // 'false', 'true'
+ // 'timeInForce': 'GTC', // GTC, IOC, FOK
+ // 'respInst': 'ACK', // ACK, 'ACCEPT, DONE
+ };
+ if (clientOrderId !== undefined) {
+ request['id'] = clientOrderId;
+ params = this.omit (params, [ 'clientOrderId', 'id' ]);
+ }
+ if ((type === 'limit') || (type === 'stop_limit')) {
+ request['orderPrice'] = this.priceToPrecision (symbol, price);
+ }
+ if ((type === 'stop_limit') || (type === 'stop_market')) {
+ const stopPrice = this.safeFloat (params, 'stopPrice');
+ if (stopPrice === undefined) {
+ throw new InvalidOrder (this.id + ' createOrder requires a stopPrice parameter for ' + type + ' orders');
+ } else {
+ request['stopPrice'] = this.priceToPrecision (symbol, stopPrice);
+ params = this.omit (params, 'stopPrice');
+ }
+ }
+ const response = await this.accountCategoryPostOrder (this.extend (request, params));
+ //
+ // {
+ // "code": 0,
+ // "data": {
+ // "ac": "MARGIN",
+ // "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
+ // "action": "place-order",
+ // "info": {
+ // "id": "16e607e2b83a8bXHbAwwoqDo55c166fa",
+ // "orderId": "16e85b4d9b9a8bXHbAwwoqDoc3d66830",
+ // "orderType": "Market",
+ // "symbol": "BTC/USDT",
+ // "timestamp": 1573576916201
+ // },
+ // "status": "Ack"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const info = this.safeValue (data, 'info', {});
+ return this.parseOrder (info, market);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'fetchOrder', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
+ const request = {
+ 'account-group': accountGroup,
+ 'account-category': accountCategory,
+ 'orderId': id,
+ };
+ const response = await this.accountCategoryGetOrderStatus (this.extend (request, params));
+ //
+ // {
+ // "code": 0,
+ // "accountCategory": "CASH",
+ // "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
+ // "data": [
+ // {
+ // "symbol": "BTC/USDT",
+ // "price": "8131.22",
+ // "orderQty": "0.00082",
+ // "orderType": "Market",
+ // "avgPx": "7392.02",
+ // "cumFee": "0.005152238",
+ // "cumFilledQty": "0.00082",
+ // "errorCode": "",
+ // "feeAsset": "USDT",
+ // "lastExecTime": 1575953151764,
+ // "orderId": "a16eee20b6750866943712zWEDdAjt3",
+ // "seqNum": 2623469,
+ // "side": "Buy",
+ // "status": "Filled",
+ // "stopPrice": "",
+ // "execInst": "NULL_VAL"
+ // }
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'fetchOpenOrders', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
+ const request = {
+ 'account-group': accountGroup,
+ 'account-category': accountCategory,
+ };
+ const response = await this.accountCategoryGetOrderOpen (this.extend (request, params));
+ //
+ // {
+ // "ac": "CASH",
+ // "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
+ // "code": 0,
+ // "data": [
+ // {
+ // "avgPx": "0", // Average filled price of the order
+ // "cumFee": "0", // cumulative fee paid for this order
+ // "cumFilledQty": "0", // cumulative filled quantity
+ // "errorCode": "", // error code; could be empty
+ // "feeAsset": "USDT", // fee asset
+ // "lastExecTime": 1576019723550, // The last execution time of the order
+ // "orderId": "s16ef21882ea0866943712034f36d83", // server provided orderId
+ // "orderQty": "0.0083", // order quantity
+ // "orderType": "Limit", // order type
+ // "price": "7105", // order price
+ // "seqNum": 8193258, // sequence number
+ // "side": "Buy", // order side
+ // "status": "New", // order status on matching engine
+ // "stopPrice": "", // only available for stop market and stop limit orders; otherwise empty
+ // "symbol": "BTC/USDT",
+ // "execInst": "NULL_VAL" // execution instruction
+ // },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ if (accountCategory === 'futures') {
+ return this.parseOrders (data, market, since, limit);
+ }
+ // a workaround for https://github.com/ccxt/ccxt/issues/7187
+ const orders = [];
+ for (let i = 0; i < data.length; i++) {
+ const order = this.parseOrder (data[i], market);
+ orders.push (order);
+ }
+ return this.filterBySymbolSinceLimit (orders, symbol, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ const defaultAccountCategory = this.safeString (this.options, 'account-category');
+ const options = this.safeValue (this.options, 'fetchClosedOrders', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
+ const request = {
+ 'account-group': accountGroup,
+ // 'category': accountCategory,
+ // 'symbol': market['id'],
+ // 'orderType': 'market', // optional, string
+ // 'side': 'buy', // or 'sell', optional, case insensitive.
+ // 'status': 'Filled', // "Filled", "Canceled", or "Rejected"
+ // 'startTime': exchange.milliseconds (),
+ // 'endTime': exchange.milliseconds (),
+ // 'page': 1,
+ // 'pageSize': 100,
+ };
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ const method = this.safeValue (options, 'method', 'accountGroupGetOrderHist');
+ if (method === 'accountGroupGetOrderHist') {
+ if (accountCategory !== undefined) {
+ request['category'] = accountCategory;
+ }
+ } else {
+ request['account-category'] = accountCategory;
+ }
+ if (since !== undefined) {
+ request['startTime'] = since;
+ }
+ if (limit !== undefined) {
+ request['pageSize'] = limit;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // accountCategoryGetOrderHistCurrent
+ //
+ // {
+ // "code":0,
+ // "accountId":"cshrHKLZCjlZ2ejqkmvIHHtPmLYqdnda",
+ // "ac":"CASH",
+ // "data":[
+ // {
+ // "seqNum":15561826728,
+ // "orderId":"a17294d305c0U6491137460bethu7kw9",
+ // "symbol":"ETH/USDT",
+ // "orderType":"Limit",
+ // "lastExecTime":1591635618200,
+ // "price":"200",
+ // "orderQty":"0.1",
+ // "side":"Buy",
+ // "status":"Canceled",
+ // "avgPx":"0",
+ // "cumFilledQty":"0",
+ // "stopPrice":"",
+ // "errorCode":"",
+ // "cumFee":"0",
+ // "feeAsset":"USDT",
+ // "execInst":"NULL_VAL"
+ // }
+ // ]
+ // }
+ //
+ // accountGroupGetOrderHist
+ //
+ // {
+ // "code": 0,
+ // "data": {
+ // "data": [
+ // {
+ // "ac": "FUTURES",
+ // "accountId": "testabcdefg",
+ // "avgPx": "0",
+ // "cumFee": "0",
+ // "cumQty": "0",
+ // "errorCode": "NULL_VAL",
+ // "execInst": "NULL_VAL",
+ // "feeAsset": "USDT",
+ // "lastExecTime": 1584072844085,
+ // "orderId": "r170d21956dd5450276356bbtcpKa74",
+ // "orderQty": "1.1499",
+ // "orderType": "Limit",
+ // "price": "4000",
+ // "sendingTime": 1584072841033,
+ // "seqNum": 24105338,
+ // "side": "Buy",
+ // "status": "Canceled",
+ // "stopPrice": "",
+ // "symbol": "BTC-PERP"
+ // },
+ // ],
+ // "hasNext": False,
+ // "limit": 500,
+ // "page": 1,
+ // "pageSize": 20
+ // }
+ // }
+ //
+ let data = this.safeValue (response, 'data');
+ const isArray = Array.isArray (data);
+ if (!isArray) {
+ data = this.safeValue (data, 'data', []);
+ }
+ return this.parseOrders (data, market, since, limit);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const market = this.market (symbol);
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'cancelOrder', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'id');
+ const request = {
+ 'account-group': accountGroup,
+ 'account-category': accountCategory,
+ 'symbol': market['id'],
+ 'time': this.milliseconds (),
+ 'id': 'foobar',
+ };
+ if (clientOrderId === undefined) {
+ request['orderId'] = id;
+ } else {
+ request['id'] = clientOrderId;
+ params = this.omit (params, [ 'clientOrderId', 'id' ]);
+ }
+ const response = await this.accountCategoryDeleteOrder (this.extend (request, params));
+ //
+ // {
+ // "code": 0,
+ // "data": {
+ // "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
+ // "ac": "CASH",
+ // "action": "cancel-order",
+ // "status": "Ack",
+ // "info": {
+ // "id": "wv8QGquoeamhssvQBeHOHGQCGlcBjj23",
+ // "orderId": "16e6198afb4s8bXHbAwwoqDo2ebc19dc",
+ // "orderType": "", // could be empty
+ // "symbol": "ETH/USDT",
+ // "timestamp": 1573594877822
+ // }
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const info = this.safeValue (data, 'info', {});
+ return this.parseOrder (info, market);
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ const defaultAccountCategory = this.safeString (this.options, 'account-category', 'cash');
+ const options = this.safeValue (this.options, 'cancelAllOrders', {});
+ let accountCategory = this.safeString (options, 'account-category', defaultAccountCategory);
+ accountCategory = this.safeString (params, 'account-category', accountCategory);
+ params = this.omit (params, 'account-category');
+ const account = this.safeValue (this.accounts, 0, {});
+ const accountGroup = this.safeValue (account, 'id');
+ const request = {
+ 'account-group': accountGroup,
+ 'account-category': accountCategory,
+ 'time': this.milliseconds (),
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ const response = await this.accountCategoryDeleteOrderAll (this.extend (request, params));
+ //
+ // {
+ // "code": 0,
+ // "data": {
+ // "ac": "CASH",
+ // "accountId": "cshQtyfq8XLAA9kcf19h8bXHbAwwoqDo",
+ // "action": "cancel-all",
+ // "info": {
+ // "id": "2bmYvi7lyTrneMzpcJcf2D7Pe9V1P9wy",
+ // "orderId": "",
+ // "orderType": "NULL_VAL",
+ // "symbol": "",
+ // "timestamp": 1574118495462
+ // },
+ // "status": "Ack"
+ // }
+ // }
+ //
+ return response;
+ }
+
+ parseDepositAddress (depositAddress, currency = undefined) {
+ //
+ // {
+ // address: "0xe7c70b4e73b6b450ee46c3b5c0f5fb127ca55722",
+ // destTag: "",
+ // tagType: "",
+ // tagId: "",
+ // chainName: "ERC20",
+ // numConfirmations: 20,
+ // withdrawalFee: 1,
+ // nativeScale: 4,
+ // tips: []
+ // }
+ //
+ const address = this.safeString (depositAddress, 'address');
+ const tagId = this.safeString (depositAddress, 'tagId');
+ const tag = this.safeString (depositAddress, tagId);
+ this.checkAddress (address);
+ const code = (currency === undefined) ? undefined : currency['code'];
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': depositAddress,
+ };
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const chainName = this.safeString (params, 'chainName');
+ params = this.omit (params, 'chainName');
+ const request = {
+ 'asset': currency['id'],
+ };
+ const response = await this.privateGetWalletDepositAddress (this.extend (request, params));
+ //
+ // {
+ // "code":0,
+ // "data":{
+ // "asset":"USDT",
+ // "assetName":"Tether",
+ // "address":[
+ // {
+ // "address":"1N22odLHXnLPCjC8kwBJPTayarr9RtPod6",
+ // "destTag":"",
+ // "tagType":"",
+ // "tagId":"",
+ // "chainName":"Omni",
+ // "numConfirmations":3,
+ // "withdrawalFee":4.7,
+ // "nativeScale":4,
+ // "tips":[]
+ // },
+ // {
+ // "address":"0xe7c70b4e73b6b450ee46c3b5c0f5fb127ca55722",
+ // "destTag":"",
+ // "tagType":"",
+ // "tagId":"",
+ // "chainName":"ERC20",
+ // "numConfirmations":20,
+ // "withdrawalFee":1.0,
+ // "nativeScale":4,
+ // "tips":[]
+ // }
+ // ]
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const addresses = this.safeValue (data, 'address', []);
+ const numAddresses = addresses.length;
+ let address = undefined;
+ if (numAddresses > 1) {
+ const addressesByChainName = this.indexBy (addresses, 'chainName');
+ if (chainName === undefined) {
+ const chainNames = Object.keys (addressesByChainName);
+ const chains = chainNames.join (', ');
+ throw new ArgumentsRequired (this.id + ' fetchDepositAddress returned more than one address, a chainName parameter is required, one of ' + chains);
+ }
+ address = this.safeValue (addressesByChainName, chainName, {});
+ } else {
+ // first address
+ address = this.safeValue (addresses, 0, {});
+ }
+ const result = this.parseDepositAddress (address, currency);
+ return this.extend (result, {
+ 'info': response,
+ });
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'txType': 'deposit',
+ };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'txType': 'withdrawal',
+ };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'asset': currency['id'],
+ // 'page': 1,
+ // 'pageSize': 20,
+ // 'startTs': this.milliseconds (),
+ // 'endTs': this.milliseconds (),
+ // 'txType': undefned, // deposit, withdrawal
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['asset'] = currency['id'];
+ }
+ if (since !== undefined) {
+ request['startTs'] = since;
+ }
+ if (limit !== undefined) {
+ request['pageSize'] = limit;
+ }
+ const response = await this.privateGetWalletTransactions (this.extend (request, params));
+ //
+ // {
+ // code: 0,
+ // data: {
+ // data: [
+ // {
+ // requestId: "wuzd1Ojsqtz4bCA3UXwtUnnJDmU8PiyB",
+ // time: 1591606166000,
+ // asset: "USDT",
+ // transactionType: "deposit",
+ // amount: "25",
+ // commission: "0",
+ // networkTransactionId: "0xbc4eabdce92f14dbcc01d799a5f8ca1f02f4a3a804b6350ea202be4d3c738fce",
+ // status: "pending",
+ // numConfirmed: 8,
+ // numConfirmations: 20,
+ // destAddress: { address: "0xe7c70b4e73b6b450ee46c3b5c0f5fb127ca55722" }
+ // }
+ // ],
+ // page: 1,
+ // pageSize: 20,
+ // hasNext: false
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const transactions = this.safeValue (data, 'data', []);
+ return this.parseTransactions (transactions, currency, since, limit);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'reviewing': 'pending',
+ 'pending': 'pending',
+ 'confirmed': 'ok',
+ 'rejected': 'rejected',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // {
+ // requestId: "wuzd1Ojsqtz4bCA3UXwtUnnJDmU8PiyB",
+ // time: 1591606166000,
+ // asset: "USDT",
+ // transactionType: "deposit",
+ // amount: "25",
+ // commission: "0",
+ // networkTransactionId: "0xbc4eabdce92f14dbcc01d799a5f8ca1f02f4a3a804b6350ea202be4d3c738fce",
+ // status: "pending",
+ // numConfirmed: 8,
+ // numConfirmations: 20,
+ // destAddress: {
+ // address: "0xe7c70b4e73b6b450ee46c3b5c0f5fb127ca55722",
+ // destTag: "..." // for currencies that have it
+ // }
+ // }
+ //
+ const id = this.safeString (transaction, 'requestId');
+ const amount = this.safeFloat (transaction, 'amount');
+ const destAddress = this.safeValue (transaction, 'destAddress', {});
+ const address = this.safeString (destAddress, 'address');
+ const tag = this.safeString (destAddress, 'destTag');
+ const txid = this.safeString (transaction, 'networkTransactionId');
+ const type = this.safeString (transaction, 'transactionType');
+ const timestamp = this.safeInteger (transaction, 'time');
+ const currencyId = this.safeString (transaction, 'asset');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const feeCost = this.safeFloat (transaction, 'commission');
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': code,
+ 'amount': amount,
+ 'address': address,
+ 'addressTo': address,
+ 'addressFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'tagFrom': undefined,
+ 'status': status,
+ 'type': type,
+ 'updated': undefined,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': {
+ 'currency': code,
+ 'cost': feeCost,
+ },
+ };
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let url = '';
+ let query = params;
+ const accountCategory = (api === 'accountCategory');
+ if (accountCategory || (api === 'accountGroup')) {
+ url += this.implodeParams ('/{account-group}', params);
+ query = this.omit (params, 'account-group');
+ }
+ const request = this.implodeParams (path, query);
+ url += '/api/pro/' + this.version;
+ if (accountCategory) {
+ url += this.implodeParams ('/{account-category}', query);
+ query = this.omit (query, 'account-category');
+ }
+ url += '/' + request;
+ query = this.omit (query, this.extractParams (path));
+ if (api === 'public') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else {
+ this.checkRequiredCredentials ();
+ const timestamp = this.milliseconds ().toString ();
+ const payload = timestamp + '+' + request;
+ const hmac = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'base64');
+ headers = {
+ 'x-auth-key': this.apiKey,
+ 'x-auth-timestamp': timestamp,
+ 'x-auth-signature': hmac,
+ };
+ if (method === 'GET') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else {
+ headers['Content-Type'] = 'application/json';
+ body = this.json (query);
+ }
+ }
+ url = this.urls['api'] + url;
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ //
+ // {'code': 6010, 'message': 'Not enough balance.'}
+ // {'code': 60060, 'message': 'The order is already filled or canceled.'}
+ // {"code":2100,"message":"ApiKeyFailure"}
+ // {"code":300001,"message":"Price is too low from market price.","reason":"INVALID_PRICE","accountId":"cshrHKLZCjlZ2ejqkmvIHHtPmLYqdnda","ac":"CASH","action":"place-order","status":"Err","info":{"symbol":"BTC/USDT"}}
+ //
+ const code = this.safeString (response, 'code');
+ const message = this.safeString (response, 'message');
+ const error = (code !== undefined) && (code !== '0');
+ if (error || (message !== undefined)) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback);
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/bitmex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitmex.js
similarity index 77%
rename from TaskServer/node_modules/ccxt/js/bitmex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitmex.js
index 9cea5dbcc..536120bf6 100644
--- a/TaskServer/node_modules/ccxt/js/bitmex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitmex.js
@@ -19,17 +19,26 @@ module.exports = class bitmex extends Exchange {
'rateLimit': 2000,
'pro': true,
'has': {
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': false,
- 'fetchOHLCV': true,
- 'withdraw': true,
+ 'createOrder': true,
'editOrder': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchMyTrades': true,
'fetchLedger': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTransactions': 'emulated',
+ 'withdraw': true,
},
'timeframes': {
'1m': '1m',
@@ -99,6 +108,7 @@ module.exports = class bitmex extends Exchange {
'user/checkReferralCode',
'user/commission',
'user/depositAddress',
+ 'user/executionHistory',
'user/margin',
'user/minWithdrawalFee',
'user/wallet',
@@ -156,6 +166,7 @@ module.exports = class bitmex extends Exchange {
'overloaded': ExchangeNotAvailable,
'Account has insufficient Available Balance': InsufficientFunds,
'Service unavailable': ExchangeNotAvailable, // {"error":{"message":"Service unavailable","name":"HTTPError"}}
+ 'Server Error': ExchangeError, // {"error":{"message":"Server Error","name":"HTTPError"}}
},
},
'precisionMode': TICK_SIZE,
@@ -253,29 +264,133 @@ module.exports = class bitmex extends Exchange {
return result;
}
- async fetchBalance (params = {}) {
- await this.loadMarkets ();
- const request = {
- 'currency': 'all',
- };
- const response = await this.privateGetUserMargin (this.extend (request, params));
+ parseBalanceResponse (response) {
+ //
+ // [
+ // {
+ // "account":1455728,
+ // "currency":"XBt",
+ // "riskLimit":1000000000000,
+ // "prevState":"",
+ // "state":"",
+ // "action":"",
+ // "amount":263542,
+ // "pendingCredit":0,
+ // "pendingDebit":0,
+ // "confirmedDebit":0,
+ // "prevRealisedPnl":0,
+ // "prevUnrealisedPnl":0,
+ // "grossComm":0,
+ // "grossOpenCost":0,
+ // "grossOpenPremium":0,
+ // "grossExecCost":0,
+ // "grossMarkValue":0,
+ // "riskValue":0,
+ // "taxableMargin":0,
+ // "initMargin":0,
+ // "maintMargin":0,
+ // "sessionMargin":0,
+ // "targetExcessMargin":0,
+ // "varMargin":0,
+ // "realisedPnl":0,
+ // "unrealisedPnl":0,
+ // "indicativeTax":0,
+ // "unrealisedProfit":0,
+ // "syntheticMargin":null,
+ // "walletBalance":263542,
+ // "marginBalance":263542,
+ // "marginBalancePcnt":1,
+ // "marginLeverage":0,
+ // "marginUsedPcnt":0,
+ // "excessMargin":263542,
+ // "excessMarginPcnt":1,
+ // "availableMargin":263542,
+ // "withdrawableMargin":263542,
+ // "timestamp":"2020-08-03T12:01:01.246Z",
+ // "grossLastValue":0,
+ // "commission":null
+ // }
+ // ]
+ //
const result = { 'info': response };
for (let i = 0; i < response.length; i++) {
const balance = response[i];
const currencyId = this.safeString (balance, 'currency');
const code = this.safeCurrencyCode (currencyId);
const account = this.account ();
- account['free'] = this.safeFloat (balance, 'availableMargin');
- account['total'] = this.safeFloat (balance, 'marginBalance');
+ let free = this.safeFloat (balance, 'availableMargin');
+ let total = this.safeFloat (balance, 'marginBalance');
if (code === 'BTC') {
- account['free'] = account['free'] * 0.00000001;
- account['total'] = account['total'] * 0.00000001;
+ if (free !== undefined) {
+ free /= 100000000;
+ }
+ if (total !== undefined) {
+ total /= 100000000;
+ }
}
+ account['free'] = free;
+ account['total'] = total;
result[code] = account;
}
return this.parseBalance (result);
}
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'currency': 'all',
+ };
+ const response = await this.privateGetUserMargin (this.extend (request, params));
+ //
+ // [
+ // {
+ // "account":1455728,
+ // "currency":"XBt",
+ // "riskLimit":1000000000000,
+ // "prevState":"",
+ // "state":"",
+ // "action":"",
+ // "amount":263542,
+ // "pendingCredit":0,
+ // "pendingDebit":0,
+ // "confirmedDebit":0,
+ // "prevRealisedPnl":0,
+ // "prevUnrealisedPnl":0,
+ // "grossComm":0,
+ // "grossOpenCost":0,
+ // "grossOpenPremium":0,
+ // "grossExecCost":0,
+ // "grossMarkValue":0,
+ // "riskValue":0,
+ // "taxableMargin":0,
+ // "initMargin":0,
+ // "maintMargin":0,
+ // "sessionMargin":0,
+ // "targetExcessMargin":0,
+ // "varMargin":0,
+ // "realisedPnl":0,
+ // "unrealisedPnl":0,
+ // "indicativeTax":0,
+ // "unrealisedProfit":0,
+ // "syntheticMargin":null,
+ // "walletBalance":263542,
+ // "marginBalance":263542,
+ // "marginBalancePcnt":1,
+ // "marginLeverage":0,
+ // "marginUsedPcnt":0,
+ // "excessMargin":263542,
+ // "excessMarginPcnt":1,
+ // "availableMargin":263542,
+ // "withdrawableMargin":263542,
+ // "timestamp":"2020-08-03T12:01:01.246Z",
+ // "grossLastValue":0,
+ // "commission":null
+ // }
+ // ]
+ //
+ return this.parseBalanceResponse (response);
+ }
+
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -505,7 +620,7 @@ module.exports = class bitmex extends Exchange {
const code = this.safeCurrencyCode (currencyId, currency);
let amount = this.safeFloat (item, 'amount');
if (amount !== undefined) {
- amount = amount * 1e-8;
+ amount = amount / 100000000;
}
let timestamp = this.parse8601 (this.safeString (item, 'transactTime'));
if (timestamp === undefined) {
@@ -516,7 +631,7 @@ module.exports = class bitmex extends Exchange {
}
let feeCost = this.safeFloat (item, 'fee', 0);
if (feeCost !== undefined) {
- feeCost = feeCost * 1e-8;
+ feeCost = feeCost / 100000000;
}
const fee = {
'cost': feeCost,
@@ -524,7 +639,7 @@ module.exports = class bitmex extends Exchange {
};
let after = this.safeFloat (item, 'walletBalance');
if (after !== undefined) {
- after = after * 1e-8;
+ after = after / 100000000;
}
const before = this.sum (after, -amount);
let direction = undefined;
@@ -662,11 +777,11 @@ module.exports = class bitmex extends Exchange {
}
let amount = this.safeInteger (transaction, 'amount');
if (amount !== undefined) {
- amount = Math.abs (amount) * 1e-8;
+ amount = Math.abs (amount) / 10000000;
}
let feeCost = this.safeInteger (transaction, 'fee');
if (feeCost !== undefined) {
- feeCost = feeCost * 1e-8;
+ feeCost = feeCost / 10000000;
}
const fee = {
'cost': feeCost,
@@ -724,7 +839,7 @@ module.exports = class bitmex extends Exchange {
result[symbol] = ticker;
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
parseTicker (ticker, market = undefined) {
@@ -875,10 +990,26 @@ module.exports = class bitmex extends Exchange {
};
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
- const timestamp = this.parse8601 (this.safeString (ohlcv, 'timestamp'));
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "timestamp":"2015-09-25T13:38:00.000Z",
+ // "symbol":"XBTUSD",
+ // "open":237.45,
+ // "high":237.45,
+ // "low":237.45,
+ // "close":237.45,
+ // "trades":0,
+ // "volume":0,
+ // "vwap":null,
+ // "lastSize":null,
+ // "turnover":0,
+ // "homeNotional":0,
+ // "foreignNotional":0
+ // }
+ //
return [
- timestamp,
+ this.parse8601 (this.safeString (ohlcv, 'timestamp')),
this.safeFloat (ohlcv, 'open'),
this.safeFloat (ohlcv, 'high'),
this.safeFloat (ohlcv, 'low'),
@@ -919,8 +1050,17 @@ module.exports = class bitmex extends Exchange {
}
const ymdhms = this.ymdhms (timestamp);
request['startTime'] = ymdhms; // starting date filter for results
+ } else {
+ request['reverse'] = true;
}
const response = await this.publicGetTradeBucketed (this.extend (request, params));
+ //
+ // [
+ // {"timestamp":"2015-09-25T13:38:00.000Z","symbol":"XBTUSD","open":237.45,"high":237.45,"low":237.45,"close":237.45,"trades":0,"volume":0,"vwap":null,"lastSize":null,"turnover":0,"homeNotional":0,"foreignNotional":0},
+ // {"timestamp":"2015-09-25T13:39:00.000Z","symbol":"XBTUSD","open":237.45,"high":237.45,"low":237.45,"close":237.45,"trades":0,"volume":0,"vwap":null,"lastSize":null,"turnover":0,"homeNotional":0,"foreignNotional":0},
+ // {"timestamp":"2015-09-25T13:40:00.000Z","symbol":"XBTUSD","open":237.45,"high":237.45,"low":237.45,"close":237.45,"trades":0,"volume":0,"vwap":null,"lastSize":null,"turnover":0,"homeNotional":0,"foreignNotional":0}
+ // ]
+ //
const result = this.parseOHLCVs (response, market, timeframe, since, limit);
if (fetchOHLCVOpenTimestamp) {
// bitmex returns the candle's close timestamp - https://github.com/ccxt/ccxt/issues/4446
@@ -1003,7 +1143,7 @@ module.exports = class bitmex extends Exchange {
// }
//
const timestamp = this.parse8601 (this.safeString (trade, 'timestamp'));
- const price = this.safeFloat (trade, 'price');
+ const price = this.safeFloat2 (trade, 'avgPx', 'price');
const amount = this.safeFloat2 (trade, 'size', 'lastQty');
const id = this.safeString (trade, 'trdMatchID');
const order = this.safeString (trade, 'orderID');
@@ -1030,16 +1170,8 @@ module.exports = class bitmex extends Exchange {
if (fee !== undefined) {
takerOrMaker = (fee['cost'] < 0) ? 'maker' : 'taker';
}
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
- }
+ const symbol = this.safeSymbol (marketId, market);
const type = this.safeStringLower (trade, 'ordType');
return {
'info': trade,
@@ -1076,18 +1208,20 @@ module.exports = class bitmex extends Exchange {
return this.safeString (statuses, status, status);
}
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'Day': 'Day',
+ 'GoodTillCancel': 'GTC',
+ 'ImmediateOrCancel': 'IOC',
+ 'FillOrKill': 'FOK',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
+ }
+
parseOrder (order, market = undefined) {
const status = this.parseOrderStatus (this.safeString (order, 'ordStatus'));
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- } else {
- const marketId = this.safeString (order, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
- }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.parse8601 (this.safeString (order, 'timestamp'));
const lastTradeTimestamp = this.parse8601 (this.safeString (order, 'transactTime'));
const price = this.safeFloat (order, 'price');
@@ -1112,6 +1246,8 @@ module.exports = class bitmex extends Exchange {
const type = this.safeStringLower (order, 'ordType');
const side = this.safeStringLower (order, 'side');
const clientOrderId = this.safeString (order, 'clOrdID');
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'timeInForce'));
+ const stopPrice = this.safeFloat (order, 'stopPx');
return {
'info': order,
'id': id,
@@ -1121,8 +1257,10 @@ module.exports = class bitmex extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -1142,6 +1280,9 @@ module.exports = class bitmex extends Exchange {
};
if (since !== undefined) {
request['startTime'] = this.iso8601 (since);
+ } else {
+ // by default reverse=false, i.e. trades are fetched since the time of market inception (year 2015 for XBTUSD)
+ request['reverse'] = true;
}
if (limit !== undefined) {
request['count'] = limit;
@@ -1180,27 +1321,46 @@ module.exports = class bitmex extends Exchange {
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
+ const market = this.market (symbol);
+ const orderType = this.capitalize (type);
const request = {
- 'symbol': this.marketId (symbol),
+ 'symbol': market['id'],
'side': this.capitalize (side),
'orderQty': amount,
- 'ordType': this.capitalize (type),
+ 'ordType': orderType,
};
if (price !== undefined) {
- request['price'] = price;
+ if (orderType === 'Stop') {
+ const stopPrice = this.safeFloat2 (params, 'stopPx', 'stopPrice');
+ request['stopPx'] = stopPrice;
+ params = this.omit (params, [ 'stopPx', 'stopPrice' ]);
+ } else {
+ request['price'] = price;
+ }
+ }
+ const clientOrderId = this.safeString2 (params, 'clOrdID', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['clOrdID'] = clientOrderId;
+ params = this.omit (params, [ 'clOrdID', 'clientOrderId' ]);
}
const response = await this.privatePostOrder (this.extend (request, params));
- const order = this.parseOrder (response);
- const id = this.safeString (order, 'id');
- this.orders[id] = order;
- return this.extend ({ 'info': response }, order);
+ return this.parseOrder (response, market);
}
async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
await this.loadMarkets ();
- const request = {
- 'orderID': id,
- };
+ const request = {};
+ const origClOrdID = this.safeString2 (params, 'origClOrdID', 'clientOrderId');
+ if (origClOrdID !== undefined) {
+ request['origClOrdID'] = origClOrdID;
+ const clientOrderId = this.safeString (params, 'clOrdID', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['clOrdID'] = clientOrderId;
+ }
+ params = this.omit (params, [ 'origClOrdID', 'clOrdID', 'clientOrderId' ]);
+ } else {
+ request['orderID'] = id;
+ }
if (amount !== undefined) {
request['orderQty'] = amount;
}
@@ -1208,32 +1368,183 @@ module.exports = class bitmex extends Exchange {
request['price'] = price;
}
const response = await this.privatePutOrder (this.extend (request, params));
- const order = this.parseOrder (response);
- this.orders[order['id']] = order;
- return this.extend ({ 'info': response }, order);
+ return this.parseOrder (response);
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
// https://github.com/ccxt/ccxt/issues/6507
- const clOrdID = this.safeValue (params, 'clOrdID');
+ const clientOrderId = this.safeString2 (params, 'clOrdID', 'clientOrderId');
const request = {};
- if (clOrdID === undefined) {
+ if (clientOrderId === undefined) {
request['orderID'] = id;
} else {
- request['clOrdID'] = clOrdID;
+ request['clOrdID'] = clientOrderId;
+ params = this.omit (params, [ 'clOrdID', 'clientOrderId' ]);
}
const response = await this.privateDeleteOrder (this.extend (request, params));
- let order = response[0];
+ const order = this.safeValue (response, 0, {});
const error = this.safeString (order, 'error');
if (error !== undefined) {
if (error.indexOf ('Unable to cancel order due to existing state') >= 0) {
throw new OrderNotFound (this.id + ' cancelOrder() failed: ' + error);
}
}
- order = this.parseOrder (order);
- this.orders[order['id']] = order;
- return this.extend ({ 'info': response }, order);
+ return this.parseOrder (order);
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ const response = await this.privateDeleteOrderAll (this.extend (request, params));
+ //
+ // [
+ // {
+ // "orderID": "string",
+ // "clOrdID": "string",
+ // "clOrdLinkID": "string",
+ // "account": 0,
+ // "symbol": "string",
+ // "side": "string",
+ // "simpleOrderQty": 0,
+ // "orderQty": 0,
+ // "price": 0,
+ // "displayQty": 0,
+ // "stopPx": 0,
+ // "pegOffsetValue": 0,
+ // "pegPriceType": "string",
+ // "currency": "string",
+ // "settlCurrency": "string",
+ // "ordType": "string",
+ // "timeInForce": "string",
+ // "execInst": "string",
+ // "contingencyType": "string",
+ // "exDestination": "string",
+ // "ordStatus": "string",
+ // "triggered": "string",
+ // "workingIndicator": true,
+ // "ordRejReason": "string",
+ // "simpleLeavesQty": 0,
+ // "leavesQty": 0,
+ // "simpleCumQty": 0,
+ // "cumQty": 0,
+ // "avgPx": 0,
+ // "multiLegReportingType": "string",
+ // "text": "string",
+ // "transactTime": "2020-06-01T09:36:35.290Z",
+ // "timestamp": "2020-06-01T09:36:35.290Z"
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market);
+ }
+
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetPosition (params);
+ // [
+ // {
+ // "account": 0,
+ // "symbol": "string",
+ // "currency": "string",
+ // "underlying": "string",
+ // "quoteCurrency": "string",
+ // "commission": 0,
+ // "initMarginReq": 0,
+ // "maintMarginReq": 0,
+ // "riskLimit": 0,
+ // "leverage": 0,
+ // "crossMargin": true,
+ // "deleveragePercentile": 0,
+ // "rebalancedPnl": 0,
+ // "prevRealisedPnl": 0,
+ // "prevUnrealisedPnl": 0,
+ // "prevClosePrice": 0,
+ // "openingTimestamp": "2020-11-09T06:53:59.892Z",
+ // "openingQty": 0,
+ // "openingCost": 0,
+ // "openingComm": 0,
+ // "openOrderBuyQty": 0,
+ // "openOrderBuyCost": 0,
+ // "openOrderBuyPremium": 0,
+ // "openOrderSellQty": 0,
+ // "openOrderSellCost": 0,
+ // "openOrderSellPremium": 0,
+ // "execBuyQty": 0,
+ // "execBuyCost": 0,
+ // "execSellQty": 0,
+ // "execSellCost": 0,
+ // "execQty": 0,
+ // "execCost": 0,
+ // "execComm": 0,
+ // "currentTimestamp": "2020-11-09T06:53:59.893Z",
+ // "currentQty": 0,
+ // "currentCost": 0,
+ // "currentComm": 0,
+ // "realisedCost": 0,
+ // "unrealisedCost": 0,
+ // "grossOpenCost": 0,
+ // "grossOpenPremium": 0,
+ // "grossExecCost": 0,
+ // "isOpen": true,
+ // "markPrice": 0,
+ // "markValue": 0,
+ // "riskValue": 0,
+ // "homeNotional": 0,
+ // "foreignNotional": 0,
+ // "posState": "string",
+ // "posCost": 0,
+ // "posCost2": 0,
+ // "posCross": 0,
+ // "posInit": 0,
+ // "posComm": 0,
+ // "posLoss": 0,
+ // "posMargin": 0,
+ // "posMaint": 0,
+ // "posAllowance": 0,
+ // "taxableMargin": 0,
+ // "initMargin": 0,
+ // "maintMargin": 0,
+ // "sessionMargin": 0,
+ // "targetExcessMargin": 0,
+ // "varMargin": 0,
+ // "realisedGrossPnl": 0,
+ // "realisedTax": 0,
+ // "realisedPnl": 0,
+ // "unrealisedGrossPnl": 0,
+ // "longBankrupt": 0,
+ // "shortBankrupt": 0,
+ // "taxBase": 0,
+ // "indicativeTaxRate": 0,
+ // "indicativeTax": 0,
+ // "unrealisedTax": 0,
+ // "unrealisedPnl": 0,
+ // "unrealisedPnlPcnt": 0,
+ // "unrealisedRoePcnt": 0,
+ // "simpleQty": 0,
+ // "simpleCost": 0,
+ // "simpleValue": 0,
+ // "simplePnl": 0,
+ // "simplePnlPcnt": 0,
+ // "avgCostPrice": 0,
+ // "avgEntryPrice": 0,
+ // "breakEvenPrice": 0,
+ // "marginCallPrice": 0,
+ // "liquidationPrice": 0,
+ // "bankruptPrice": 0,
+ // "timestamp": "2020-11-09T06:53:59.894Z",
+ // "lastPrice": 0,
+ // "lastValue": 0
+ // }
+ // ]
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
}
isFiat (currency) {
@@ -1263,7 +1574,7 @@ module.exports = class bitmex extends Exchange {
const response = await this.privatePostUserRequestWithdrawal (this.extend (request, params));
return {
'info': response,
- 'id': response['transactID'],
+ 'id': this.safeString (response, 'transactID'),
};
}
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitpanda.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitpanda.js
new file mode 100644
index 000000000..41f855168
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitpanda.js
@@ -0,0 +1,1811 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { AuthenticationError, ExchangeError, PermissionDenied, BadRequest, ArgumentsRequired, OrderNotFound, InsufficientFunds, ExchangeNotAvailable, DDoSProtection, InvalidAddress, InvalidOrder } = require ('./base/errors');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class bitpanda extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'bitpanda',
+ 'name': 'Bitpanda Pro',
+ 'countries': [ 'AT' ], // Austria
+ 'rateLimit': 300,
+ 'version': 'v1',
+ // new metainfo interface
+ 'has': {
+ 'CORS': false,
+ 'publicAPI': true,
+ 'privateAPI': true,
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'cancelOrders': true,
+ 'createDepositAddress': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchDeposits': true,
+ 'fetchDepositAddress': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrderTrades': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchTradingFees': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
+ },
+ 'timeframes': {
+ '1m': '1/MINUTES',
+ '5m': '5/MINUTES',
+ '15m': '15/MINUTES',
+ '30m': '30/MINUTES',
+ '1h': '1/HOURS',
+ '4h': '4/HOURS',
+ '1d': '1/DAYS',
+ '1w': '1/WEEKS',
+ '1M': '1/MONTHS',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87591171-9a377d80-c6f0-11ea-94ac-97a126eac3bc.jpg',
+ 'api': {
+ 'public': 'https://api.exchange.bitpanda.com/public',
+ 'private': 'https://api.exchange.bitpanda.com/public',
+ },
+ 'www': 'https://www.bitpanda.com/en/pro',
+ 'doc': [
+ 'https://developers.bitpanda.com/exchange/',
+ ],
+ 'fees': 'https://www.bitpanda.com/en/pro/fees',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'currencies',
+ 'candlesticks/{instrument_code}',
+ 'fees',
+ 'instruments',
+ 'order-book/{instrument_code}',
+ 'market-ticker',
+ 'market-ticker/{instrument_code}',
+ 'price-ticks/{instrument_code}',
+ 'time',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'account/balances',
+ 'account/deposit/crypto/{currency_code}',
+ 'account/deposit/fiat/EUR',
+ 'account/deposits',
+ 'account/deposits/bitpanda',
+ 'account/withdrawals',
+ 'account/withdrawals/bitpanda',
+ 'account/fees',
+ 'account/orders',
+ 'account/orders/{order_id}',
+ 'account/orders/{order_id}/trades',
+ 'account/trades',
+ 'account/trades/{trade_id}',
+ 'account/trading-volume',
+ ],
+ 'post': [
+ 'account/deposit/crypto',
+ 'account/withdraw/crypto',
+ 'account/withdraw/fiat',
+ 'account/fees',
+ 'account/orders',
+ ],
+ 'delete': [
+ 'account/orders',
+ 'account/orders/{order_id}',
+ 'account/orders/client/{client_id}',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.15 / 100,
+ 'maker': 0.10 / 100,
+ 'tiers': [
+ // volume in BTC
+ {
+ 'taker': [
+ [0, 0.15 / 100],
+ [100, 0.13 / 100],
+ [250, 0.13 / 100],
+ [1000, 0.1 / 100],
+ [5000, 0.09 / 100],
+ [10000, 0.075 / 100],
+ [20000, 0.065 / 100],
+ ],
+ 'maker': [
+ [0, 0.1 / 100],
+ [100, 0.1 / 100],
+ [250, 0.09 / 100],
+ [1000, 0.075 / 100],
+ [5000, 0.06 / 100],
+ [10000, 0.05 / 100],
+ [20000, 0.05 / 100],
+ ],
+ },
+ ],
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': false,
+ },
+ 'exceptions': {
+ 'exact': {
+ 'INVALID_CLIENT_UUID': InvalidOrder,
+ 'ORDER_NOT_FOUND': OrderNotFound,
+ 'ONLY_ONE_ERC20_ADDRESS_ALLOWED': InvalidAddress,
+ 'DEPOSIT_ADDRESS_NOT_USED': InvalidAddress,
+ 'INVALID_CREDENTIALS': AuthenticationError,
+ 'MISSING_CREDENTIALS': AuthenticationError,
+ 'INVALID_APIKEY': AuthenticationError,
+ 'INVALID_SCOPES': AuthenticationError,
+ 'INVALID_SUBJECT': AuthenticationError,
+ 'INVALID_ISSUER': AuthenticationError,
+ 'INVALID_AUDIENCE': AuthenticationError,
+ 'INVALID_DEVICE_ID': AuthenticationError,
+ 'INVALID_IP_RESTRICTION': AuthenticationError,
+ 'APIKEY_REVOKED': AuthenticationError,
+ 'APIKEY_EXPIRED': AuthenticationError,
+ 'SYNCHRONIZER_TOKEN_MISMATCH': AuthenticationError,
+ 'SESSION_EXPIRED': AuthenticationError,
+ 'INTERNAL_ERROR': AuthenticationError,
+ 'CLIENT_IP_BLOCKED': PermissionDenied,
+ 'MISSING_PERMISSION': PermissionDenied,
+ 'ILLEGAL_CHARS': BadRequest,
+ 'UNSUPPORTED_MEDIA_TYPE': BadRequest,
+ 'ACCOUNT_HISTORY_TIME_RANGE_TOO_BIG': BadRequest,
+ 'CANDLESTICKS_TIME_RANGE_TOO_BIG': BadRequest,
+ 'INVALID_INSTRUMENT_CODE': BadRequest,
+ 'INVALID_ORDER_TYPE': BadRequest,
+ 'INVALID_UNIT': BadRequest,
+ 'INVALID_PERIOD': BadRequest,
+ 'INVALID_TIME': BadRequest,
+ 'INVALID_DATE': BadRequest,
+ 'INVALID_CURRENCY': BadRequest,
+ 'INVALID_AMOUNT': BadRequest,
+ 'INVALID_PRICE': BadRequest,
+ 'INVALID_LIMIT': BadRequest,
+ 'INVALID_QUERY': BadRequest,
+ 'INVALID_CURSOR': BadRequest,
+ 'INVALID_ACCOUNT_ID': BadRequest,
+ 'INVALID_SIDE': InvalidOrder,
+ 'INVALID_ACCOUNT_HISTORY_FROM_TIME': BadRequest,
+ 'INVALID_ACCOUNT_HISTORY_MAX_PAGE_SIZE': BadRequest,
+ 'INVALID_ACCOUNT_HISTORY_TIME_PERIOD': BadRequest,
+ 'INVALID_ACCOUNT_HISTORY_TO_TIME': BadRequest,
+ 'INVALID_CANDLESTICKS_GRANULARITY': BadRequest,
+ 'INVALID_CANDLESTICKS_UNIT': BadRequest,
+ 'INVALID_ORDER_BOOK_DEPTH': BadRequest,
+ 'INVALID_ORDER_BOOK_LEVEL': BadRequest,
+ 'INVALID_PAGE_CURSOR': BadRequest,
+ 'INVALID_TIME_RANGE': BadRequest,
+ 'INVALID_TRADE_ID': BadRequest,
+ 'INVALID_UI_ACCOUNT_SETTINGS': BadRequest,
+ 'NEGATIVE_AMOUNT': InvalidOrder,
+ 'NEGATIVE_PRICE': InvalidOrder,
+ 'MIN_SIZE_NOT_SATISFIED': InvalidOrder,
+ 'BAD_AMOUNT_PRECISION': InvalidOrder,
+ 'BAD_PRICE_PRECISION': InvalidOrder,
+ 'BAD_TRIGGER_PRICE_PRECISION': InvalidOrder,
+ 'MAX_OPEN_ORDERS_EXCEEDED': BadRequest,
+ 'MISSING_PRICE': InvalidOrder,
+ 'MISSING_ORDER_TYPE': InvalidOrder,
+ 'MISSING_SIDE': InvalidOrder,
+ 'MISSING_CANDLESTICKS_PERIOD_PARAM': ArgumentsRequired,
+ 'MISSING_CANDLESTICKS_UNIT_PARAM': ArgumentsRequired,
+ 'MISSING_FROM_PARAM': ArgumentsRequired,
+ 'MISSING_INSTRUMENT_CODE': ArgumentsRequired,
+ 'MISSING_ORDER_ID': InvalidOrder,
+ 'MISSING_TO_PARAM': ArgumentsRequired,
+ 'MISSING_TRADE_ID': ArgumentsRequired,
+ 'INVALID_ORDER_ID': OrderNotFound,
+ 'NOT_FOUND': OrderNotFound,
+ 'INSUFFICIENT_LIQUIDITY': InsufficientFunds,
+ 'INSUFFICIENT_FUNDS': InsufficientFunds,
+ 'NO_TRADING': ExchangeNotAvailable,
+ 'SERVICE_UNAVAILABLE': ExchangeNotAvailable,
+ 'GATEWAY_TIMEOUT': ExchangeNotAvailable,
+ 'RATELIMIT': DDoSProtection,
+ 'CF_RATELIMIT': DDoSProtection,
+ 'INTERNAL_SERVER_ERROR': ExchangeError,
+ },
+ 'broad': {
+ },
+ },
+ 'commonCurrencies': {
+ 'MIOTA': 'IOTA', // https://github.com/ccxt/ccxt/issues/7487
+ },
+ // exchange-specific options
+ 'options': {
+ 'fetchTradingFees': {
+ 'method': 'fetchPrivateTradingFees', // or 'fetchPublicTradingFees'
+ },
+ 'fiat': [ 'EUR', 'CHF' ],
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // {
+ // iso: '2020-07-10T05:17:26.716Z',
+ // epoch_millis: 1594358246716,
+ // }
+ //
+ return this.safeInteger (response, 'epoch_millis');
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCurrencies (params);
+ //
+ // [
+ // {
+ // "code":"BEST",
+ // "precision":8
+ // }
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const currency = response[i];
+ const id = this.safeString (currency, 'code');
+ const code = this.safeCurrencyCode (id);
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'name': undefined,
+ 'info': currency, // the original payload
+ 'active': undefined,
+ 'fee': undefined,
+ 'precision': this.safeInteger (currency, 'precision'),
+ 'limits': {
+ 'amount': { 'min': undefined, 'max': undefined },
+ 'price': { 'min': undefined, 'max': undefined },
+ 'cost': { 'min': undefined, 'max': undefined },
+ 'withdraw': { 'min': undefined, 'max': undefined },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetInstruments (params);
+ //
+ // [
+ // {
+ // state: 'ACTIVE',
+ // base: { code: 'ETH', precision: 8 },
+ // quote: { code: 'CHF', precision: 2 },
+ // amount_precision: 4,
+ // market_precision: 2,
+ // min_size: '10.0'
+ // }
+ // ]
+ //
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ const baseAsset = this.safeValue (market, 'base', {});
+ const quoteAsset = this.safeValue (market, 'quote', {});
+ const baseId = this.safeString (baseAsset, 'code');
+ const quoteId = this.safeString (quoteAsset, 'code');
+ const id = baseId + '_' + quoteId;
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const precision = {
+ 'amount': this.safeInteger (market, 'amount_precision'),
+ 'price': this.safeInteger (market, 'market_precision'),
+ };
+ const limits = {
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': this.safeFloat (market, 'min_size'),
+ 'max': undefined,
+ },
+ };
+ const state = this.safeString (market, 'state');
+ const active = (state === 'ACTIVE');
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'precision': precision,
+ 'limits': limits,
+ 'info': market,
+ 'active': active,
+ });
+ }
+ return result;
+ }
+
+ async fetchTradingFees (params = {}) {
+ let method = this.safeString (params, 'method');
+ params = this.omit (params, 'method');
+ if (method === undefined) {
+ const options = this.safeValue (this.options, 'fetchTradingFees', {});
+ method = this.safeString (options, 'method', 'fetchPrivateTradingFees');
+ }
+ return await this[method] (params);
+ }
+
+ async fetchPublicTradingFees (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetFees (params);
+ //
+ // [
+ // {
+ // "fee_group_id":"default",
+ // "display_text":"The standard fee plan.",
+ // "fee_tiers":[
+ // {"volume":"0.0","fee_group_id":"default","maker_fee":"0.1","taker_fee":"0.15"},
+ // {"volume":"100.0","fee_group_id":"default","maker_fee":"0.1","taker_fee":"0.13"},
+ // {"volume":"250.0","fee_group_id":"default","maker_fee":"0.09","taker_fee":"0.13"},
+ // {"volume":"1000.0","fee_group_id":"default","maker_fee":"0.075","taker_fee":"0.1"},
+ // {"volume":"5000.0","fee_group_id":"default","maker_fee":"0.06","taker_fee":"0.09"},
+ // {"volume":"10000.0","fee_group_id":"default","maker_fee":"0.05","taker_fee":"0.075"},
+ // {"volume":"20000.0","fee_group_id":"default","maker_fee":"0.05","taker_fee":"0.065"}
+ // ],
+ // "fee_discount_rate":"25.0",
+ // "minimum_price_value":"0.12"
+ // }
+ // ]
+ //
+ const feeGroupsById = this.indexBy (response, 'fee_group_id');
+ const feeGroupId = this.safeValue (this.options, 'fee_group_id', 'default');
+ const feeGroup = this.safeValue (feeGroupsById, feeGroupId, {});
+ const feeTiers = this.safeValue (feeGroup, 'fee_tiers');
+ const result = {};
+ for (let i = 0; i < this.symbols.length; i++) {
+ const symbol = this.symbols[i];
+ const fee = {
+ 'info': feeGroup,
+ 'symbol': symbol,
+ 'maker': undefined,
+ 'taker': undefined,
+ 'percentage': true,
+ 'tierBased': true,
+ };
+ const takerFees = [];
+ const makerFees = [];
+ for (let i = 0; i < feeTiers.length; i++) {
+ const tier = feeTiers[i];
+ const volume = this.safeFloat (tier, 'volume');
+ let taker = this.safeFloat (tier, 'taker_fee');
+ let maker = this.safeFloat (tier, 'maker_fee');
+ taker /= 100;
+ maker /= 100;
+ takerFees.push ([ volume, taker ]);
+ makerFees.push ([ volume, maker ]);
+ if (i === 0) {
+ fee['taker'] = taker;
+ fee['maker'] = maker;
+ }
+ }
+ const tiers = {
+ 'taker': takerFees,
+ 'maker': makerFees,
+ };
+ fee['tiers'] = tiers;
+ result[symbol] = fee;
+ }
+ return result;
+ }
+
+ async fetchPrivateTradingFees (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccountFees (params);
+ //
+ // {
+ // "account_id": "ed524d00-820a-11e9-8f1e-69602df16d85",
+ // "running_trading_volume": "0.0",
+ // "fee_group_id": "default",
+ // "collect_fees_in_best": false,
+ // "fee_discount_rate": "25.0",
+ // "minimum_price_value": "0.12",
+ // "fee_tiers": [
+ // { "volume": "0.0", "fee_group_id": "default", "maker_fee": "0.1", "taker_fee": "0.1" },
+ // { "volume": "100.0", "fee_group_id": "default", "maker_fee": "0.09", "taker_fee": "0.1" },
+ // { "volume": "250.0", "fee_group_id": "default", "maker_fee": "0.08", "taker_fee": "0.1" },
+ // { "volume": "1000.0", "fee_group_id": "default", "maker_fee": "0.07", "taker_fee": "0.09" },
+ // { "volume": "5000.0", "fee_group_id": "default", "maker_fee": "0.06", "taker_fee": "0.08" },
+ // { "volume": "10000.0", "fee_group_id": "default", "maker_fee": "0.05", "taker_fee": "0.07" },
+ // { "volume": "20000.0", "fee_group_id": "default", "maker_fee": "0.05", "taker_fee": "0.06" },
+ // { "volume": "50000.0", "fee_group_id": "default", "maker_fee": "0.05", "taker_fee": "0.05" }
+ // ],
+ // "active_fee_tier": { "volume": "0.0", "fee_group_id": "default", "maker_fee": "0.1", "taker_fee": "0.1" }
+ // }
+ //
+ const activeFeeTier = this.safeValue (response, 'active_fee_tier', {});
+ const result = {
+ 'info': response,
+ 'maker': this.safeFloat (activeFeeTier, 'maker_fee'),
+ 'taker': this.safeFloat (activeFeeTier, 'taker_fee'),
+ 'percentage': true,
+ 'tierBased': true,
+ };
+ const feeTiers = this.safeValue (response, 'fee_tiers');
+ const takerFees = [];
+ const makerFees = [];
+ for (let i = 0; i < feeTiers.length; i++) {
+ const tier = feeTiers[i];
+ const volume = this.safeFloat (tier, 'volume');
+ let taker = this.safeFloat (tier, 'taker_fee');
+ let maker = this.safeFloat (tier, 'maker_fee');
+ taker /= 100;
+ maker /= 100;
+ takerFees.push ([ volume, taker ]);
+ makerFees.push ([ volume, maker ]);
+ }
+ const tiers = {
+ 'taker': takerFees,
+ 'maker': makerFees,
+ };
+ result['tiers'] = tiers;
+ return result;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker, fetchTickers
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "sequence":602562,
+ // "time":"2020-07-10T06:27:34.951Z",
+ // "state":"ACTIVE",
+ // "is_frozen":0,
+ // "quote_volume":"1695555.1783768",
+ // "base_volume":"205.67436",
+ // "last_price":"8143.91",
+ // "best_bid":"8143.71",
+ // "best_ask":"8156.9",
+ // "price_change":"-147.47",
+ // "price_change_percentage":"-1.78",
+ // "high":"8337.45",
+ // "low":"8110.0"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (ticker, 'time'));
+ const marketId = this.safeString (ticker, 'instrument_code');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const last = this.safeFloat (ticker, 'last_price');
+ const percentage = this.safeFloat (ticker, 'price_change_percentage');
+ const change = this.safeFloat (ticker, 'price_change');
+ let open = undefined;
+ let average = undefined;
+ if ((last !== undefined) && (change !== undefined)) {
+ open = last - change;
+ average = this.sum (last, open) / 2;
+ }
+ const baseVolume = this.safeFloat (ticker, 'base_volume');
+ const quoteVolume = this.safeFloat (ticker, 'quote_volume');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': this.safeFloat (ticker, 'best_bid'),
+ 'bidVolume': undefined,
+ 'ask': this.safeFloat (ticker, 'best_ask'),
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'instrument_code': market['id'],
+ };
+ const response = await this.publicGetMarketTickerInstrumentCode (this.extend (request, params));
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "sequence":602562,
+ // "time":"2020-07-10T06:27:34.951Z",
+ // "state":"ACTIVE",
+ // "is_frozen":0,
+ // "quote_volume":"1695555.1783768",
+ // "base_volume":"205.67436",
+ // "last_price":"8143.91",
+ // "best_bid":"8143.71",
+ // "best_ask":"8156.9",
+ // "price_change":"-147.47",
+ // "price_change_percentage":"-1.78",
+ // "high":"8337.45",
+ // "low":"8110.0"
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetMarketTicker (params);
+ //
+ // [
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "sequence":602562,
+ // "time":"2020-07-10T06:27:34.951Z",
+ // "state":"ACTIVE",
+ // "is_frozen":0,
+ // "quote_volume":"1695555.1783768",
+ // "base_volume":"205.67436",
+ // "last_price":"8143.91",
+ // "best_bid":"8143.71",
+ // "best_ask":"8156.9",
+ // "price_change":"-147.47",
+ // "price_change_percentage":"-1.78",
+ // "high":"8337.45",
+ // "low":"8110.0"
+ // }
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const ticker = this.parseTicker (response[i]);
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'instrument_code': this.marketId (symbol),
+ // level 1 means only the best bid and ask
+ // level 2 is a compiled order book up to market precision
+ // level 3 is a full orderbook
+ // if you wish to get regular updates about orderbooks please use the Websocket channel
+ // heavy usage of this endpoint may result in limited access according to rate limits rules
+ // 'level': 3, // default
+ };
+ if (limit !== undefined) {
+ request['depth'] = limit;
+ }
+ const response = await this.publicGetOrderBookInstrumentCode (this.extend (request, params));
+ //
+ // level 1
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "time":"2020-07-10T07:39:06.343Z",
+ // "asks":{
+ // "value":{
+ // "price":"8145.29",
+ // "amount":"0.96538",
+ // "number_of_orders":1
+ // }
+ // },
+ // "bids":{
+ // "value":{
+ // "price":"8134.0",
+ // "amount":"1.5978",
+ // "number_of_orders":5
+ // }
+ // }
+ // }
+ //
+ // level 2
+ //
+ // {
+ // "instrument_code":"BTC_EUR","time":"2020-07-10T07:36:43.538Z",
+ // "asks":[
+ // {"price":"8146.59","amount":"0.89691","number_of_orders":1},
+ // {"price":"8146.89","amount":"1.92062","number_of_orders":1},
+ // {"price":"8169.5","amount":"0.0663","number_of_orders":1},
+ // ],
+ // "bids":[
+ // {"price":"8143.49","amount":"0.01329","number_of_orders":1},
+ // {"price":"8137.01","amount":"5.34748","number_of_orders":1},
+ // {"price":"8137.0","amount":"2.0","number_of_orders":1},
+ // ]
+ // }
+ //
+ // level 3
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "time":"2020-07-10T07:32:31.525Z",
+ // "bids":[
+ // {"price":"8146.79","amount":"0.01537","order_id":"5d717da1-a8f4-422d-afcc-03cb6ab66825"},
+ // {"price":"8139.32","amount":"3.66009","order_id":"d0715c68-f28d-4cf1-a450-d56cf650e11c"},
+ // {"price":"8137.51","amount":"2.61049","order_id":"085fd6f4-e835-4ca5-9449-a8f165772e60"},
+ // ],
+ // "asks":[
+ // {"price":"8153.49","amount":"0.93384","order_id":"755d3aa3-42b5-46fa-903d-98f42e9ae6c4"},
+ // {"price":"8153.79","amount":"1.80456","order_id":"62034cf3-b70d-45ff-b285-ba6307941e7c"},
+ // {"price":"8167.9","amount":"0.0018","order_id":"036354e0-71cd-492f-94f2-01f7d4b66422"},
+ // ]
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (response, 'time'));
+ return this.parseOrderBook (response, timestamp, 'bids', 'asks', 'price', 'amount');
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "granularity":{"unit":"HOURS","period":1},
+ // "high":"9252.65",
+ // "low":"9115.27",
+ // "open":"9250.0",
+ // "close":"9132.35",
+ // "total_amount":"33.85924",
+ // "volume":"311958.9635744",
+ // "time":"2020-05-08T22:59:59.999Z",
+ // "last_sequence":461123
+ // }
+ //
+ const granularity = this.safeValue (ohlcv, 'granularity');
+ const unit = this.safeString (granularity, 'unit');
+ const period = this.safeString (granularity, 'period');
+ const units = {
+ 'MINUTES': 'm',
+ 'HOURS': 'h',
+ 'DAYS': 'd',
+ 'WEEKS': 'w',
+ 'MONTHS': 'M',
+ };
+ const lowercaseUnit = this.safeString (units, unit);
+ const timeframe = period + lowercaseUnit;
+ const durationInSeconds = this.parseTimeframe (timeframe);
+ const duration = durationInSeconds * 1000;
+ const timestamp = this.parse8601 (this.safeString (ohlcv, 'time'));
+ const alignedTimestamp = duration * parseInt (timestamp / duration);
+ const options = this.safeValue (this.options, 'fetchOHLCV', {});
+ const volumeField = this.safeString (options, 'volume', 'total_amount');
+ return [
+ alignedTimestamp,
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, volumeField),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const periodUnit = this.safeString (this.timeframes, timeframe);
+ const [ period, unit ] = periodUnit.split ('/');
+ const durationInSeconds = this.parseTimeframe (timeframe);
+ const duration = durationInSeconds * 1000;
+ if (limit === undefined) {
+ limit = 1500;
+ }
+ const request = {
+ 'instrument_code': market['id'],
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()),
+ 'period': period,
+ 'unit': unit,
+ };
+ if (since === undefined) {
+ const now = this.milliseconds ();
+ request['to'] = this.iso8601 (now);
+ request['from'] = this.iso8601 (now - limit * duration);
+ } else {
+ request['from'] = this.iso8601 (since);
+ request['to'] = this.iso8601 (this.sum (since, limit * duration));
+ }
+ const response = await this.publicGetCandlesticksInstrumentCode (this.extend (request, params));
+ //
+ // [
+ // {"instrument_code":"BTC_EUR","granularity":{"unit":"HOURS","period":1},"high":"9252.65","low":"9115.27","open":"9250.0","close":"9132.35","total_amount":"33.85924","volume":"311958.9635744","time":"2020-05-08T22:59:59.999Z","last_sequence":461123},
+ // {"instrument_code":"BTC_EUR","granularity":{"unit":"HOURS","period":1},"high":"9162.49","low":"9040.0","open":"9132.53","close":"9083.69","total_amount":"26.19685","volume":"238553.7812365","time":"2020-05-08T23:59:59.999Z","last_sequence":461376},
+ // {"instrument_code":"BTC_EUR","granularity":{"unit":"HOURS","period":1},"high":"9135.7","low":"9002.59","open":"9055.45","close":"9133.98","total_amount":"26.21919","volume":"238278.8724959","time":"2020-05-09T00:59:59.999Z","last_sequence":461521},
+ // ]
+ //
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "price":"8137.28",
+ // "amount":"0.22269",
+ // "taker_side":"BUY",
+ // "volume":"1812.0908832",
+ // "time":"2020-07-10T14:44:32.299Z",
+ // "trade_timestamp":1594392272299,
+ // "sequence":603047
+ // }
+ //
+ // fetchMyTrades, fetchOrder, fetchOpenOrders, fetchClosedOrders trades (private)
+ //
+ // {
+ // "fee": {
+ // "fee_amount": "0.0014",
+ // "fee_currency": "BTC",
+ // "fee_percentage": "0.1",
+ // "fee_group_id": "default",
+ // "fee_type": "TAKER",
+ // "running_trading_volume": "0.0"
+ // },
+ // "trade": {
+ // "trade_id": "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
+ // "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "amount": "1.4",
+ // "side": "BUY",
+ // "instrument_code": "BTC_EUR",
+ // "price": "7341.4",
+ // "time": "2019-09-27T15:05:32.564Z",
+ // "sequence": 48670
+ // }
+ // }
+ //
+ const feeInfo = this.safeValue (trade, 'fee', {});
+ trade = this.safeValue (trade, 'trade', trade);
+ const timestamp = this.parse8601 (this.safeString (trade, 'time'));
+ const side = this.safeStringLower2 (trade, 'side', 'taker_side');
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'amount');
+ let cost = this.safeFloat (trade, 'volume');
+ if ((cost === undefined) && (amount !== undefined) && (price !== undefined)) {
+ cost = amount * price;
+ }
+ const marketId = this.safeString (trade, 'instrument_code');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const feeCost = this.safeFloat (feeInfo, 'fee_amount');
+ let takerOrMaker = undefined;
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (feeInfo, 'fee_currency');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ const feeRate = this.safeFloat (feeInfo, 'fee_percentage');
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ 'rate': feeRate,
+ };
+ takerOrMaker = this.safeStringLower (feeInfo, 'fee_type');
+ }
+ return {
+ 'id': this.safeString2 (trade, 'trade_id', 'sequence'),
+ 'order': this.safeString (trade, 'order_id'),
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'type': undefined,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'takerOrMaker': takerOrMaker,
+ 'fee': fee,
+ 'info': trade,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'instrument_code': market['id'],
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()),
+ };
+ if (since !== undefined) {
+ // returns price ticks for a specific market with an interval of maximum of 4 hours
+ // sorted by latest first
+ request['from'] = this.iso8601 (since);
+ request['to'] = this.iso8601 (this.sum (since, 14400000));
+ }
+ const response = await this.publicGetPriceTicksInstrumentCode (this.extend (request, params));
+ //
+ // [
+ // {
+ // "instrument_code":"BTC_EUR",
+ // "price":"8137.28",
+ // "amount":"0.22269",
+ // "taker_side":"BUY",
+ // "volume":"1812.0908832",
+ // "time":"2020-07-10T14:44:32.299Z",
+ // "trade_timestamp":1594392272299,
+ // "sequence":603047
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccountBalances (params);
+ //
+ // {
+ // "account_id":"4b95934f-55f1-460c-a525-bd5afc0cf071",
+ // "balances":[
+ // {
+ // "account_id":"4b95934f-55f1-460c-a525-bd5afc0cf071",
+ // "currency_code":"BTC",
+ // "change":"10.0",
+ // "available":"10.0",
+ // "locked":"0.0",
+ // "sequence":142135994,
+ // "time":"2020-07-01T10:57:32.959Z"
+ // }
+ // ]
+ // }
+ //
+ const balances = this.safeValue (response, 'balances', []);
+ const result = { 'info': response };
+ for (let i = 0; i < balances.length; i++) {
+ const balance = balances[i];
+ const currencyId = this.safeString (balance, 'currency_code');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['free'] = this.safeFloat (balance, 'available');
+ account['used'] = this.safeFloat (balance, 'locked');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ parseDepositAddress (depositAddress, currency = undefined) {
+ let code = undefined;
+ if (currency !== undefined) {
+ code = currency['code'];
+ }
+ const address = this.safeString (depositAddress, 'address');
+ const tag = this.safeString (depositAddress, 'destination_tag');
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': depositAddress,
+ };
+ }
+
+ async createDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privatePostAccountDepositCrypto (this.extend (request, params));
+ //
+ // {
+ // "address":"rBnNhk95FrdNisZtXcStzriFS8vEzz53DM",
+ // "destination_tag":"865690307",
+ // "enabled":true,
+ // "is_smart_contract":false
+ // }
+ //
+ return this.parseDepositAddress (response, currency);
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency_code': currency['id'],
+ };
+ const response = await this.privateGetAccountDepositCryptoCurrencyCode (this.extend (request, params));
+ //
+ // {
+ // "address":"rBnNhk95FrdNisZtXcStzriFS8vEzz53DM",
+ // "destination_tag":"865690307",
+ // "enabled":true,
+ // "is_smart_contract":false,
+ // "can_create_more":false
+ // }
+ //
+ return this.parseDepositAddress (response, currency);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'cursor': 'string', // pointer specifying the position from which the next pages should be returned
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency_code'] = currency['id'];
+ }
+ if (limit !== undefined) {
+ request['max_page_size'] = limit;
+ }
+ if (since !== undefined) {
+ const to = this.safeString (params, 'to');
+ if (to === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchDeposits requires a "to" iso8601 string param with the since argument is specified');
+ }
+ request['from'] = this.iso8601 (since);
+ }
+ const response = await this.privateGetAccountDeposits (this.extend (request, params));
+ //
+ // {
+ // "deposit_history": [
+ // {
+ // "transaction_id": "e5342efcd-d5b7-4a56-8e12-b69ffd68c5ef",
+ // "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
+ // "amount": "100",
+ // "type": "CRYPTO",
+ // "funds_source": "INTERNAL",
+ // "time": "2020-04-22T09:57:47Z",
+ // "currency": "BTC",
+ // "fee_amount": "0.0",
+ // "fee_currency": "BTC"
+ // },
+ // {
+ // "transaction_id": "79793d00-2899-4a4d-95b7-73ae6b31384f",
+ // "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
+ // "time": "2020-05-05T11:22:07.925Z",
+ // "currency": "EUR",
+ // "funds_source": "EXTERNAL",
+ // "type": "FIAT",
+ // "amount": "50.0",
+ // "fee_amount": "0.01",
+ // "fee_currency": "EUR"
+ // }
+ // ],
+ // "max_page_size": 2,
+ // "cursor": "eyJhY2NvdW50X2lkIjp7InMiOiJlMzY5YWM4MC00NTc3LTExZTktYWUwOC05YmVkYzQ3OTBiODQiLCJzcyI6W10sIm5zIjpbXSwiYnMiOltdLCJtIjp7fSwibCI6W119LCJpdGVtX2tleSI6eyJzIjoiV0lUSERSQVdBTDo6MmFlMjYwY2ItOTk3MC00YmNiLTgxNmEtZGY4MDVmY2VhZTY1Iiwic3MiOltdLCJucyI6W10sImJzIjpbXSwibSI6e30sImwiOltdfSwiZ2xvYmFsX3dpdGhkcmF3YWxfaW5kZXhfaGFzaF9rZXkiOnsicyI6ImUzNjlhYzgwLTQ1NzctMTFlOS1hZTA4LTliZWRjNDc5MGI4NCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX0sInRpbWVzdGFtcCI6eyJuIjoiMTU4ODA1ODc2Nzk0OCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX19"
+ // }
+ //
+ const depositHistory = this.safeValue (response, 'deposit_history', []);
+ return this.parseTransactions (depositHistory, currency, since, limit, { 'type': 'deposit' });
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'cursor': 'string', // pointer specifying the position from which the next pages should be returned
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency_code'] = currency['id'];
+ }
+ if (limit !== undefined) {
+ request['max_page_size'] = limit;
+ }
+ if (since !== undefined) {
+ const to = this.safeString (params, 'to');
+ if (to === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchWithdrawals requires a "to" iso8601 string param with the since argument is specified');
+ }
+ request['from'] = this.iso8601 (since);
+ }
+ const response = await this.privateGetAccountWithdrawals (this.extend (request, params));
+ //
+ // {
+ // "withdrawal_history": [
+ // {
+ // "account_id": "e369ac80-4577-11e9-ae08-9bedc4790b84",
+ // "amount": "0.1",
+ // "currency": "BTC",
+ // "fee_amount": "0.00002",
+ // "fee_currency": "BTC",
+ // "funds_source": "EXTERNAL",
+ // "related_transaction_id": "e298341a-3855-405e-bce3-92db368a3157",
+ // "time": "2020-05-05T11:11:32.110Z",
+ // "transaction_id": "6693ff40-bb10-4dcf-ada7-3b287727c882",
+ // "type": "CRYPTO"
+ // },
+ // {
+ // "account_id": "e369ac80-4577-11e9-ae08-9bedc4790b84",
+ // "amount": "0.1",
+ // "currency": "BTC",
+ // "fee_amount": "0.0",
+ // "fee_currency": "BTC",
+ // "funds_source": "INTERNAL",
+ // "time": "2020-05-05T10:29:53.464Z",
+ // "transaction_id": "ec9703b1-954b-4f76-adea-faac66eabc0b",
+ // "type": "CRYPTO"
+ // }
+ // ],
+ // "cursor": "eyJhY2NvdW50X2lkIjp7InMiOiJlMzY5YWM4MC00NTc3LTExZTktYWUwOC05YmVkYzQ3OTBiODQiLCJzcyI6W10sIm5zIjpbXSwiYnMiOltdLCJtIjp7fSwibCI6W119LCJpdGVtX2tleSI6eyJzIjoiV0lUSERSQVdBTDo6ZWM5NzAzYjEtOTU0Yi00Zjc2LWFkZWEtZmFhYzY2ZWFiYzBiIiwic3MiOltdLCJucyI6W10sImJzIjpbXSwibSI6e30sImwiOltdfSwiZ2xvYmFsX3dpdGhkcmF3YWxfaW5kZXhfaGFzaF9rZXkiOnsicyI6ImUzNjlhYzgwLTQ1NzctMTFlOS1hZTA4LTliZWRjNDc5MGI4NCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX0sInRpbWVzdGFtcCI6eyJuIjoiMTU4ODY3NDU5MzQ2NCIsInNzIjpbXSwibnMiOltdLCJicyI6W10sIm0iOnt9LCJsIjpbXX19",
+ // "max_page_size": 2
+ // }
+ //
+ const withdrawalHistory = this.safeValue (response, 'withdrawal_history', []);
+ return this.parseTransactions (withdrawalHistory, currency, since, limit, { 'type': 'withdrawal' });
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': code,
+ 'amount': this.currencyToPrecision (code, amount),
+ // 'payout_account_id': '66756a10-3e86-48f4-9678-b634c4b135b2', // fiat only
+ // 'recipient': { // crypto only
+ // 'address': address,
+ // // 'destination_tag': '',
+ // },
+ };
+ const options = this.safeValue (this.options, 'fiat', []);
+ const isFiat = this.inArray (code, options);
+ const method = isFiat ? 'privatePostAccountWithdrawFiat' : 'privatePostAccountWithdrawCrypto';
+ if (isFiat) {
+ const payoutAccountId = this.safeString (params, 'payout_account_id');
+ if (payoutAccountId === undefined) {
+ throw ArgumentsRequired (this.id + ' withdraw() requires a payout_account_id param for fiat ' + code + ' withdrawals');
+ }
+ } else {
+ const recipient = { 'address': address };
+ if (tag !== undefined) {
+ recipient['destination_tag'] = tag;
+ }
+ request['recipient'] = recipient;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // crypto
+ //
+ // {
+ // "amount": "1234.5678",
+ // "fee": "1234.5678",
+ // "recipient": "3NacQ7rzZdhfyAtfJ5a11k8jFPdcMP2Bq7",
+ // "destination_tag": "",
+ // "transaction_id": "d0f8529f-f832-4e6a-9dc5-b8d5797badb2"
+ // }
+ //
+ // fiat
+ //
+ // {
+ // "transaction_id": "54236cd0-4413-11e9-93fb-5fea7e5b5df6"
+ // }
+ //
+ return this.parseTransaction (response, currency);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // fetchDeposits, fetchWithdrawals
+ //
+ // {
+ // "transaction_id": "C2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
+ // "type": "FIAT",
+ // "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
+ // "amount": "1234.5678",
+ // "time": "2019-08-24T14:15:22Z",
+ // "funds_source": "INTERNAL",
+ // "currency": "BTC",
+ // "fee_amount": "1234.5678",
+ // "fee_currency": "BTC",
+ // "blockchain_transaction_id": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16",
+ // "related_transaction_id": "e298341a-3855-405e-bce3-92db368a3157"
+ // }
+ //
+ // withdraw
+ //
+ //
+ // crypto
+ //
+ // {
+ // "amount": "1234.5678",
+ // "fee": "1234.5678",
+ // "recipient": "3NacQ7rzZdhfyAtfJ5a11k8jFPdcMP2Bq7",
+ // "destination_tag": "",
+ // "transaction_id": "d0f8529f-f832-4e6a-9dc5-b8d5797badb2"
+ // }
+ //
+ // fiat
+ //
+ // {
+ // "transaction_id": "54236cd0-4413-11e9-93fb-5fea7e5b5df6"
+ // }
+ //
+ const id = this.safeString (transaction, 'transaction_id');
+ const amount = this.safeFloat (transaction, 'amount');
+ const timestamp = this.parse8601 (this.safeString (transaction, 'time'));
+ const currencyId = this.safeString (transaction, 'currency');
+ currency = this.safeCurrency (currencyId, currency);
+ const status = 'ok'; // the exchange returns cleared transactions only
+ const feeCost = this.safeFloat2 (transaction, 'fee_amount', 'fee');
+ let fee = undefined;
+ const addressTo = this.safeString (transaction, 'recipient');
+ const tagTo = this.safeString (transaction, 'destination_tag');
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (transaction, 'fee_currency', currencyId);
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': currency['code'],
+ 'amount': amount,
+ 'address': addressTo,
+ 'addressFrom': undefined,
+ 'addressTo': addressTo,
+ 'tag': tagTo,
+ 'tagFrom': undefined,
+ 'tagTo': tagTo,
+ 'status': status,
+ 'type': undefined,
+ 'updated': undefined,
+ 'txid': this.safeString (transaction, 'blockchain_transaction_id'),
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': fee,
+ };
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'FILLED': 'open',
+ 'FILLED_FULLY': 'closed',
+ 'FILLED_CLOSED': 'canceled',
+ 'FILLED_REJECTED': 'rejected',
+ 'OPEN': 'open',
+ 'REJECTED': 'rejected',
+ 'CLOSED': 'canceled',
+ 'FAILED': 'failed',
+ 'STOP_TRIGGERED': 'triggered',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // "order_id": "d5492c24-2995-4c18-993a-5b8bf8fffc0d",
+ // "client_id": "d75fb03b-b599-49e9-b926-3f0b6d103206",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "instrument_code": "BTC_EUR",
+ // "time": "2019-08-01T08:00:44.026Z",
+ // "side": "BUY",
+ // "price": "5000",
+ // "amount": "1",
+ // "filled_amount": "0.5",
+ // "type": "LIMIT",
+ // "time_in_force": "GOOD_TILL_CANCELLED"
+ // }
+ //
+ // fetchOrder, fetchOpenOrders, fetchClosedOrders
+ //
+ // {
+ // "order": {
+ // "order_id": "66756a10-3e86-48f4-9678-b634c4b135b2",
+ // "account_id": "1eb2ad5d-55f1-40b5-bc92-7dc05869e905",
+ // "instrument_code": "BTC_EUR",
+ // "amount": "1234.5678",
+ // "filled_amount": "1234.5678",
+ // "side": "BUY",
+ // "type": "LIMIT",
+ // "status": "OPEN",
+ // "sequence": 123456789,
+ // "price": "1234.5678",
+ // "average_price": "1234.5678",
+ // "reason": "INSUFFICIENT_FUNDS",
+ // "time": "2019-08-24T14:15:22Z",
+ // "time_in_force": "GOOD_TILL_CANCELLED",
+ // "time_last_updated": "2019-08-24T14:15:22Z",
+ // "expire_after": "2019-08-24T14:15:22Z",
+ // "is_post_only": false,
+ // "time_triggered": "2019-08-24T14:15:22Z",
+ // "trigger_price": "1234.5678"
+ // },
+ // "trades": [
+ // {
+ // "fee": {
+ // "fee_amount": "0.0014",
+ // "fee_currency": "BTC",
+ // "fee_percentage": "0.1",
+ // "fee_group_id": "default",
+ // "fee_type": "TAKER",
+ // "running_trading_volume": "0.0"
+ // },
+ // "trade": {
+ // "trade_id": "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
+ // "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "amount": "1.4",
+ // "side": "BUY",
+ // "instrument_code": "BTC_EUR",
+ // "price": "7341.4",
+ // "time": "2019-09-27T15:05:32.564Z",
+ // "sequence": 48670
+ // }
+ // }
+ // ]
+ // }
+ //
+ const rawTrades = this.safeValue (order, 'trades', []);
+ order = this.safeValue (order, 'order', order);
+ const id = this.safeString (order, 'order_id');
+ const clientOrderId = this.safeString (order, 'client_id');
+ const timestamp = this.parse8601 (this.safeString (order, 'time'));
+ let status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const marketId = this.safeString (order, 'instrument_code');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'amount');
+ let cost = undefined;
+ const filled = this.safeFloat (order, 'filled_amount');
+ let remaining = undefined;
+ if (filled !== undefined) {
+ if (amount !== undefined) {
+ remaining = Math.max (0, amount - filled);
+ if (status === undefined) {
+ if (remaining > 0) {
+ status = 'open';
+ } else {
+ status = 'closed';
+ }
+ }
+ }
+ }
+ const side = this.safeStringLower (order, 'side');
+ const type = this.safeStringLower (order, 'type');
+ const trades = this.parseTrades (rawTrades, market, undefined, undefined);
+ const fees = [];
+ const numTrades = trades.length;
+ let lastTradeTimestamp = undefined;
+ let tradeCost = undefined;
+ let tradeAmount = undefined;
+ if (numTrades > 0) {
+ lastTradeTimestamp = trades[0]['timestamp'];
+ tradeCost = 0;
+ tradeAmount = 0;
+ for (let i = 0; i < trades.length; i++) {
+ const trade = trades[i];
+ fees.push (trade['fee']);
+ lastTradeTimestamp = Math.max (lastTradeTimestamp, trade['timestamp']);
+ tradeCost = this.sum (tradeCost, trade['cost']);
+ tradeAmount = this.sum (tradeAmount, trade['amount']);
+ }
+ }
+ let average = this.safeFloat (order, 'average_price');
+ if (average === undefined) {
+ if ((tradeCost !== undefined) && (tradeAmount !== undefined) && (tradeAmount !== 0)) {
+ average = tradeCost / tradeAmount;
+ }
+ }
+ if (cost === undefined) {
+ if ((average !== undefined) && (filled !== undefined)) {
+ cost = average * filled;
+ }
+ }
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'time_in_force'));
+ const stopPrice = this.safeFloat (order, 'trigger_price');
+ const result = {
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'info': order,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': timeInForce,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': stopPrice,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ // 'fee': undefined,
+ 'trades': trades,
+ };
+ const numFees = fees.length;
+ if (numFees > 0) {
+ if (numFees === 1) {
+ result['fee'] = fees[0];
+ } else {
+ const feesByCurrency = this.groupBy (fees, 'currency');
+ const feeCurrencies = Object.keys (feesByCurrency);
+ const numFeesByCurrency = feeCurrencies.length;
+ if (numFeesByCurrency === 1) {
+ const feeCurrency = feeCurrencies[0];
+ const feeArray = this.safeValue (feesByCurrency, feeCurrency);
+ let feeCost = 0;
+ for (let i = 0; i < feeArray.length; i++) {
+ feeCost = this.sum (feeCost, feeArray[i]['cost']);
+ }
+ result['fee'] = {
+ 'cost': feeCost,
+ 'currency': feeCurrency,
+ };
+ } else {
+ result['fees'] = fees;
+ }
+ }
+ } else {
+ result['fee'] = undefined;
+ }
+ return result;
+ }
+
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'GOOD_TILL_CANCELLED': 'GTC',
+ 'GOOD_TILL_TIME': 'GTT',
+ 'IMMEDIATE_OR_CANCELLED': 'IOC',
+ 'FILL_OR_KILL': 'FOK',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const uppercaseType = type.toUpperCase ();
+ const request = {
+ 'instrument_code': market['id'],
+ 'type': uppercaseType, // LIMIT, MARKET, STOP
+ 'side': side.toUpperCase (), // or SELL
+ 'amount': this.amountToPrecision (symbol, amount),
+ // "price": "1234.5678", // required for LIMIT and STOP orders
+ // "client_id": "d75fb03b-b599-49e9-b926-3f0b6d103206", // optional
+ // "time_in_force": "GOOD_TILL_CANCELLED", // limit orders only, GOOD_TILL_CANCELLED, GOOD_TILL_TIME, IMMEDIATE_OR_CANCELLED and FILL_OR_KILL
+ // "expire_after": "2020-07-02T19:40:13Z", // required for GOOD_TILL_TIME
+ // "is_post_only": false, // limit orders only, optional
+ // "trigger_price": "1234.5678" // required for stop orders
+ };
+ let priceIsRequired = false;
+ if (uppercaseType === 'LIMIT' || uppercaseType === 'STOP') {
+ priceIsRequired = true;
+ }
+ if (uppercaseType === 'STOP') {
+ const triggerPrice = this.safeFloat (params, 'trigger_price');
+ if (triggerPrice === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder requires a trigger_price param for ' + type + ' orders');
+ }
+ request['trigger_price'] = this.priceToPrecision (symbol, triggerPrice);
+ params = this.omit (params, 'trigger_price');
+ }
+ if (priceIsRequired) {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_id');
+ if (clientOrderId !== undefined) {
+ request['client_id'] = clientOrderId;
+ params = this.omit (params, [ 'clientOrderId', 'client_id' ]);
+ }
+ const response = await this.privatePostAccountOrders (this.extend (request, params));
+ //
+ // {
+ // "order_id": "d5492c24-2995-4c18-993a-5b8bf8fffc0d",
+ // "client_id": "d75fb03b-b599-49e9-b926-3f0b6d103206",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "instrument_code": "BTC_EUR",
+ // "time": "2019-08-01T08:00:44.026Z",
+ // "side": "BUY",
+ // "price": "5000",
+ // "amount": "1",
+ // "filled_amount": "0.5",
+ // "type": "LIMIT",
+ // "time_in_force": "GOOD_TILL_CANCELLED"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_id');
+ params = this.omit (params, [ 'clientOrderId', 'client_id' ]);
+ let method = 'privateDeleteAccountOrdersOrderId';
+ const request = {};
+ if (clientOrderId !== undefined) {
+ method = 'privateDeleteAccountOrdersClientClientId';
+ request['client_id'] = clientOrderId;
+ } else {
+ request['order_id'] = id;
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // responds with an empty body
+ //
+ return response;
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ if (symbol !== undefined) {
+ const market = this.market (symbol);
+ request['instrument_code'] = market['id'];
+ }
+ const response = await this.privateDeleteAccountOrders (this.extend (request, params));
+ //
+ // [
+ // "a10e9bd1-8f72-4cfe-9f1b-7f1c8a9bd8ee"
+ // ]
+ //
+ return response;
+ }
+
+ async cancelOrders (ids, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'ids': ids.join (','),
+ };
+ const response = await this.privateDeleteAccountOrders (this.extend (request, params));
+ //
+ // [
+ // "a10e9bd1-8f72-4cfe-9f1b-7f1c8a9bd8ee"
+ // ]
+ //
+ return response;
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'order_id': id,
+ };
+ const response = await this.privateGetAccountOrdersOrderId (this.extend (request, params));
+ //
+ // {
+ // "order": {
+ // "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "time_last_updated": "2019-09-27T15:05:35.096Z",
+ // "sequence": 48782,
+ // "price": "7349.2",
+ // "filled_amount": "100.0",
+ // "status": "FILLED_FULLY",
+ // "amount": "100.0",
+ // "instrument_code": "BTC_EUR",
+ // "side": "BUY",
+ // "time": "2019-09-27T15:05:32.063Z",
+ // "type": "MARKET"
+ // },
+ // "trades": [
+ // {
+ // "fee": {
+ // "fee_amount": "0.0014",
+ // "fee_currency": "BTC",
+ // "fee_percentage": "0.1",
+ // "fee_group_id": "default",
+ // "fee_type": "TAKER",
+ // "running_trading_volume": "0.0"
+ // },
+ // "trade": {
+ // "trade_id": "fdff2bcc-37d6-4a2d-92a5-46e09c868664",
+ // "order_id": "36bb2437-7402-4794-bf26-4bdf03526439",
+ // "account_id": "a4c699f6-338d-4a26-941f-8f9853bfc4b9",
+ // "amount": "1.4",
+ // "side": "BUY",
+ // "instrument_code": "BTC_EUR",
+ // "price": "7341.4",
+ // "time": "2019-09-27T15:05:32.564Z",
+ // "sequence": 48670
+ // }
+ // }
+ // ]
+ // }
+ //
+ return this.parseOrder (response);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()), // max range is 100 days
+ // 'instrument_code': market['id'],
+ // 'with_cancelled_and_rejected': false, // default is false, orders which have been cancelled by the user before being filled or rejected by the system as invalid, additionally, all inactive filled orders which would return with "with_just_filled_inactive"
+ // 'with_just_filled_inactive': false, // orders which have been filled and are no longer open, use of "with_cancelled_and_rejected" extends "with_just_filled_inactive" and in case both are specified the latter is ignored
+ // 'with_just_orders': false, // do not return any trades corresponsing to the orders, it may be significanly faster and should be used if user is not interesting in trade information
+ // 'max_page_size': 100,
+ // 'cursor': 'string', // pointer specifying the position from which the next pages should be returned
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['instrument_code'] = market['id'];
+ }
+ if (since !== undefined) {
+ const to = this.safeString (params, 'to');
+ if (to === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrders requires a "to" iso8601 string param with the since argument is specified, max range is 100 days');
+ }
+ request['from'] = this.iso8601 (since);
+ }
+ if (limit !== undefined) {
+ request['max_page_size'] = limit;
+ }
+ const response = await this.privateGetAccountOrders (this.extend (request, params));
+ //
+ // {
+ // "order_history": [
+ // {
+ // "order": {
+ // "trigger_price": "12089.88",
+ // "order_id": "d453ca12-c650-46dd-9dee-66910d96bfc0",
+ // "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
+ // "instrument_code": "BTC_USDT",
+ // "time": "2019-08-23T10:02:31.663Z",
+ // "side": "SELL",
+ // "price": "10159.76",
+ // "average_price": "10159.76",
+ // "amount": "0.2",
+ // "filled_amount": "0.2",
+ // "type": "STOP",
+ // "sequence": 8,
+ // "status": "FILLED_FULLY"
+ // },
+ // "trades": [
+ // {
+ // "fee": {
+ // "fee_amount": "0.4188869",
+ // "fee_currency": "USDT",
+ // "fee_percentage": "0.1",
+ // "fee_group_id": "default",
+ // "fee_type": "TAKER",
+ // "running_trading_volume": "0.0"
+ // },
+ // "trade": {
+ // "trade_id": "ec82896f-fd1b-4cbb-89df-a9da85ccbb4b",
+ // "order_id": "d453ca12-c650-46dd-9dee-66910d96bfc0",
+ // "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
+ // "amount": "0.2",
+ // "side": "SELL",
+ // "instrument_code": "BTC_USDT",
+ // "price": "10159.76",
+ // "time": "2019-08-23T10:02:32.663Z",
+ // "sequence": 9
+ // }
+ // }
+ // ]
+ // },
+ // {
+ // "order": {
+ // "order_id": "5151a99e-f414-418f-8cf1-2568d0a63ea5",
+ // "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
+ // "instrument_code": "BTC_USDT",
+ // "time": "2019-08-23T10:01:36.773Z",
+ // "side": "SELL",
+ // "price": "12289.88",
+ // "amount": "0.5",
+ // "filled_amount": "0.0",
+ // "type": "LIMIT",
+ // "sequence": 7,
+ // "status": "OPEN"
+ // },
+ // "trades": []
+ // },
+ // {
+ // "order": {
+ // "order_id": "ac80d857-75e1-4733-9070-fd4288395fdc",
+ // "account_id": "ef3a5f4c-cfcd-415e-ba89-5a9abf47b28a",
+ // "instrument_code": "BTC_USDT",
+ // "time": "2019-08-23T10:01:25.031Z",
+ // "side": "SELL",
+ // "price": "11089.88",
+ // "amount": "0.1",
+ // "filled_amount": "0.0",
+ // "type": "LIMIT",
+ // "sequence": 6,
+ // "status": "OPEN"
+ // },
+ // "trades": []
+ // }
+ // ],
+ // "max_page_size": 100
+ // }
+ //
+ const orderHistory = this.safeValue (response, 'order_history', []);
+ return this.parseOrders (orderHistory, market, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'with_cancelled_and_rejected': true, // default is false, orders which have been cancelled by the user before being filled or rejected by the system as invalid, additionally, all inactive filled orders which would return with "with_just_filled_inactive"
+ };
+ return await this.fetchOpenOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'order_id': id,
+ // 'max_page_size': 100,
+ // 'cursor': 'string', // pointer specifying the position from which the next pages should be returned
+ };
+ if (limit !== undefined) {
+ request['max_page_size'] = limit;
+ }
+ const response = await this.privateGetAccountOrdersOrderIdTrades (this.extend (request, params));
+ //
+ // {
+ // "trade_history": [
+ // {
+ // "trade": {
+ // "trade_id": "2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
+ // "order_id": "66756a10-3e86-48f4-9678-b634c4b135b2",
+ // "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
+ // "amount": "1234.5678",
+ // "side": "BUY",
+ // "instrument_code": "BTC_EUR",
+ // "price": "1234.5678",
+ // "time": "2019-08-24T14:15:22Z",
+ // "price_tick_sequence": 0,
+ // "sequence": 123456789
+ // },
+ // "fee": {
+ // "fee_amount": "1234.5678",
+ // "fee_percentage": "1234.5678",
+ // "fee_group_id": "default",
+ // "running_trading_volume": "1234.5678",
+ // "fee_currency": "BTC",
+ // "fee_type": "TAKER"
+ // }
+ // }
+ // ],
+ // "max_page_size": 0,
+ // "cursor": "string"
+ // }
+ //
+ const tradeHistory = this.safeValue (response, 'trade_history', []);
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ return this.parseTrades (tradeHistory, market, since, limit);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()), // max range is 100 days
+ // 'instrument_code': market['id'],
+ // 'max_page_size': 100,
+ // 'cursor': 'string', // pointer specifying the position from which the next pages should be returned
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['instrument_code'] = market['id'];
+ }
+ if (since !== undefined) {
+ const to = this.safeString (params, 'to');
+ if (to === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a "to" iso8601 string param with the since argument is specified, max range is 100 days');
+ }
+ request['from'] = this.iso8601 (since);
+ }
+ if (limit !== undefined) {
+ request['max_page_size'] = limit;
+ }
+ const response = await this.privateGetAccountTrades (this.extend (request, params));
+ //
+ // {
+ // "trade_history": [
+ // {
+ // "trade": {
+ // "trade_id": "2b42efcd-d5b7-4a56-8e12-b69ffd68c5ef",
+ // "order_id": "66756a10-3e86-48f4-9678-b634c4b135b2",
+ // "account_id": "c2d0076a-c20d-41f8-9e9a-1a1d028b2b58",
+ // "amount": "1234.5678",
+ // "side": "BUY",
+ // "instrument_code": "BTC_EUR",
+ // "price": "1234.5678",
+ // "time": "2019-08-24T14:15:22Z",
+ // "price_tick_sequence": 0,
+ // "sequence": 123456789
+ // },
+ // "fee": {
+ // "fee_amount": "1234.5678",
+ // "fee_percentage": "1234.5678",
+ // "fee_group_id": "default",
+ // "running_trading_volume": "1234.5678",
+ // "fee_currency": "BTC",
+ // "fee_type": "TAKER"
+ // }
+ // }
+ // ],
+ // "max_page_size": 0,
+ // "cursor": "string"
+ // }
+ //
+ const tradeHistory = this.safeValue (response, 'trade_history', []);
+ return this.parseTrades (tradeHistory, market, since, limit);
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let url = this.urls['api'][api] + '/' + this.version + '/' + this.implodeParams (path, params);
+ const query = this.omit (params, this.extractParams (path));
+ if (api === 'public') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (api === 'private') {
+ this.checkRequiredCredentials ();
+ headers = {
+ 'Accept': 'application/json',
+ 'Authorization': 'Bearer ' + this.apiKey,
+ };
+ if (method === 'POST') {
+ body = this.json (query);
+ headers['Content-Type'] = 'application/json';
+ } else {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return;
+ }
+ //
+ // {"error":"MISSING_FROM_PARAM"}
+ // {"error":"MISSING_TO_PARAM"}
+ // {"error":"CANDLESTICKS_TIME_RANGE_TOO_BIG"}
+ //
+ const message = this.safeString (response, 'error');
+ if (message !== undefined) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/bitso.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitso.js
similarity index 81%
rename from TaskServer/node_modules/ccxt/js/bitso.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitso.js
index b5f853005..8ef7dc93c 100644
--- a/TaskServer/node_modules/ccxt/js/bitso.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitso.js
@@ -4,6 +4,7 @@
const Exchange = require ('./base/Exchange');
const { ExchangeError, InvalidNonce, AuthenticationError, OrderNotFound } = require ('./base/errors');
+const { TICK_SIZE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -16,26 +17,37 @@ module.exports = class bitso extends Exchange {
'rateLimit': 2000, // 30 requests per minute
'version': 'v3',
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchDepositAddress': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27766335-715ce7aa-5ed5-11e7-88a8-173a27bb30fe.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295554-11f98280-c50e-11ea-80d6-15b3bafa8cbf.jpg',
'api': 'https://api.bitso.com',
'www': 'https://bitso.com',
'doc': 'https://bitso.com/api_info',
- 'fees': 'https://bitso.com/fees?l=es',
+ 'fees': 'https://bitso.com/fees',
'referral': 'https://bitso.com/?ref=itej',
},
+ 'precisionMode': TICK_SIZE,
'options': {
'precision': {
- 'XRP': 6,
- 'MXN': 2,
- 'TUSD': 2,
+ 'XRP': 0.000001,
+ 'MXN': 0.01,
+ 'TUSD': 0.01,
},
- 'defaultPrecision': 8,
+ 'defaultPrecision': 0.00000001,
},
'api': {
'public': {
@@ -100,6 +112,38 @@ module.exports = class bitso extends Exchange {
async fetchMarkets (params = {}) {
const response = await this.publicGetAvailableBooks (params);
+ //
+ // {
+ // "success":true,
+ // "payload":[
+ // {
+ // "book":"btc_mxn",
+ // "minimum_price":"500",
+ // "maximum_price":"10000000",
+ // "minimum_amount":"0.00005",
+ // "maximum_amount":"500",
+ // "minimum_value":"5",
+ // "maximum_value":"10000000",
+ // "tick_size":"0.01",
+ // "fees":{
+ // "flat_rate":{"maker":"0.500","taker":"0.650"},
+ // "structure":[
+ // {"volume":"1500000","maker":"0.00500","taker":"0.00650"},
+ // {"volume":"2000000","maker":"0.00490","taker":"0.00637"},
+ // {"volume":"5000000","maker":"0.00480","taker":"0.00624"},
+ // {"volume":"7000000","maker":"0.00440","taker":"0.00572"},
+ // {"volume":"10000000","maker":"0.00420","taker":"0.00546"},
+ // {"volume":"15000000","maker":"0.00400","taker":"0.00520"},
+ // {"volume":"35000000","maker":"0.00370","taker":"0.00481"},
+ // {"volume":"50000000","maker":"0.00300","taker":"0.00390"},
+ // {"volume":"150000000","maker":"0.00200","taker":"0.00260"},
+ // {"volume":"250000000","maker":"0.00100","taker":"0.00130"},
+ // {"volume":"9999999999","maker":"0.00000","taker":"0.00130"},
+ // ]
+ // }
+ // },
+ // ]
+ // }
const markets = this.safeValue (response, 'payload');
const result = [];
for (let i = 0; i < markets.length; i++) {
@@ -125,11 +169,43 @@ module.exports = class bitso extends Exchange {
'max': this.safeFloat (market, 'maximum_value'),
},
};
+ const defaultPricePrecision = this.safeFloat (this.options['precision'], quote, this.options['defaultPrecision']);
+ const pricePrecision = this.safeFloat (market, 'tick_size', defaultPricePrecision);
const precision = {
- 'amount': this.safeInteger (this.options['precision'], base, this.options['defaultPrecision']),
- 'price': this.safeInteger (this.options['precision'], quote, this.options['defaultPrecision']),
+ 'amount': this.safeFloat (this.options['precision'], base, this.options['defaultPrecision']),
+ 'price': pricePrecision,
};
- result.push ({
+ const fees = this.safeValue (market, 'fees', {});
+ const flatRate = this.safeValue (fees, 'flat_rate', {});
+ const maker = this.safeFloat (flatRate, 'maker');
+ const taker = this.safeFloat (flatRate, 'taker');
+ const feeTiers = this.safeValue (fees, 'structure', []);
+ const fee = {
+ 'maker': maker,
+ 'taker': taker,
+ 'percentage': true,
+ 'tierBased': true,
+ };
+ const takerFees = [];
+ const makerFees = [];
+ for (let i = 0; i < feeTiers.length; i++) {
+ const tier = feeTiers[i];
+ const volume = this.safeFloat (tier, 'volume');
+ const takerFee = this.safeFloat (tier, 'taker');
+ const makerFee = this.safeFloat (tier, 'maker');
+ takerFees.push ([ volume, takerFee ]);
+ makerFees.push ([ volume, makerFee ]);
+ if (i === 0) {
+ fee['taker'] = taker;
+ fee['maker'] = maker;
+ }
+ }
+ const tiers = {
+ 'taker': takerFees,
+ 'maker': makerFees,
+ };
+ fee['tiers'] = tiers;
+ result.push (this.extend ({
'id': id,
'symbol': symbol,
'base': base,
@@ -140,7 +216,7 @@ module.exports = class bitso extends Exchange {
'limits': limits,
'precision': precision,
'active': undefined,
- });
+ }, fee));
}
return result;
}
@@ -216,16 +292,8 @@ module.exports = class bitso extends Exchange {
parseTrade (trade, market = undefined) {
const timestamp = this.parse8601 (this.safeString (trade, 'created_at'));
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (trade, 'book');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (trade, 'book');
+ const symbol = this.safeSymbol (marketId, market, '_');
const side = this.safeString2 (trade, 'side', 'maker_side');
let amount = this.safeFloat2 (trade, 'amount', 'major');
if (amount !== undefined) {
@@ -342,23 +410,8 @@ module.exports = class bitso extends Exchange {
const id = this.safeString (order, 'oid');
const side = this.safeString (order, 'side');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let symbol = undefined;
const marketId = this.safeString (order, 'book');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const orderType = this.safeString (order, 'type');
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const price = this.safeFloat (order, 'price');
@@ -380,8 +433,10 @@ module.exports = class bitso extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': orderType,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': undefined,
'remaining': remaining,
@@ -456,10 +511,10 @@ module.exports = class bitso extends Exchange {
const response = await this.privateGetFundingDestination (this.extend (request, params));
let address = this.safeString (response['payload'], 'account_identifier');
let tag = undefined;
- if (code === 'XRP') {
+ if (address.indexOf ('?dt=') >= 0) {
const parts = address.split ('?dt=');
- address = parts[0];
- tag = parts[1];
+ address = this.safeString (parts, 0);
+ tag = this.safeString (parts, 1);
}
this.checkAddress (address);
return {
diff --git a/TaskServer/node_modules/ccxt/js/bitstamp.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitstamp.js
similarity index 71%
rename from TaskServer/node_modules/ccxt/js/bitstamp.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitstamp.js
index 74d767234..1b4a33a46 100644
--- a/TaskServer/node_modules/ccxt/js/bitstamp.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitstamp.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { AuthenticationError, ExchangeError, NotSupported, PermissionDenied, InvalidNonce, OrderNotFound, InsufficientFunds, InvalidAddress, InvalidOrder } = require ('./base/errors');
+const { AuthenticationError, ExchangeError, NotSupported, PermissionDenied, InvalidNonce, OrderNotFound, InsufficientFunds, InvalidAddress, InvalidOrder, ArgumentsRequired, OnMaintenance } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -19,13 +19,27 @@ module.exports = class bitstamp extends Exchange {
'pro': true,
'has': {
'CORS': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchDepositAddress': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
+ 'fetchMarkets': true,
+ 'fetchCurrencies': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
'fetchTransactions': true,
'fetchWithdrawals': true,
'withdraw': true,
+ 'fetchTradingFee': true,
+ 'fetchTradingFees': true,
+ 'fetchFundingFees': true,
+ 'fetchFees': true,
+ 'fetchLedger': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27786377-8c8ab57e-5fe9-11e7-8ea4-2b05b6bcceec.jpg',
@@ -37,6 +51,20 @@ module.exports = class bitstamp extends Exchange {
'www': 'https://www.bitstamp.net',
'doc': 'https://www.bitstamp.net/api',
},
+ 'timeframes': {
+ '1m': '60',
+ '3m': '180',
+ '5m': '300',
+ '15m': '900',
+ '30m': '1800',
+ '1h': '3600',
+ '2h': '7200',
+ '4h': '14400',
+ '6h': '21600',
+ '12h': '43200',
+ '1d': '86400',
+ '1w': '259200',
+ },
'requiredCredentials': {
'apiKey': true,
'secret': true,
@@ -45,6 +73,7 @@ module.exports = class bitstamp extends Exchange {
'api': {
'public': {
'get': [
+ 'ohlc/{pair}/',
'order_book/{pair}/',
'ticker_hour/{pair}/',
'ticker/{pair}/',
@@ -76,6 +105,16 @@ module.exports = class bitstamp extends Exchange {
'eth_address/',
'xrp_withdrawal/',
'xrp_address/',
+ 'xlm_withdrawal/',
+ 'xlm_address/',
+ 'pax_withdrawal/',
+ 'pax_address/',
+ 'link_withdrawal/',
+ 'link_address/',
+ 'usdc_withdrawal/',
+ 'usdc_address/',
+ 'omg_withdrawal/',
+ 'omg_address/',
'transfer-to-main/',
'transfer-from-main/',
'withdrawal-requests/',
@@ -114,7 +153,13 @@ module.exports = class bitstamp extends Exchange {
[2000000, 0.13 / 100],
[4000000, 0.12 / 100],
[20000000, 0.11 / 100],
- [20000001, 0.10 / 100],
+ [50000000, 0.10 / 100],
+ [100000000, 0.07 / 100],
+ [500000000, 0.05 / 100],
+ [2000000000, 0.03 / 100],
+ [6000000000, 0.01 / 100],
+ [10000000000, 0.005 / 100],
+ [10000000001, 0.0],
],
'maker': [
[0, 0.5 / 100],
@@ -127,7 +172,13 @@ module.exports = class bitstamp extends Exchange {
[2000000, 0.13 / 100],
[4000000, 0.12 / 100],
[20000000, 0.11 / 100],
- [20000001, 0.10 / 100],
+ [50000000, 0.10 / 100],
+ [100000000, 0.07 / 100],
+ [500000000, 0.05 / 100],
+ [2000000000, 0.03 / 100],
+ [6000000000, 0.01 / 100],
+ [10000000000, 0.005 / 100],
+ [10000000001, 0.0],
],
},
},
@@ -135,13 +186,15 @@ module.exports = class bitstamp extends Exchange {
'tierBased': false,
'percentage': false,
'withdraw': {
- 'BTC': 0,
- 'BCH': 0,
- 'LTC': 0,
- 'ETH': 0,
- 'XRP': 0,
+ 'BTC': 0.0005,
+ 'BCH': 0.0001,
+ 'LTC': 0.001,
+ 'ETH': 0.001,
+ 'XRP': 0.02,
+ 'XLM': 0.005,
+ 'PAX': 0.5,
'USD': 25,
- 'EUR': 0.90,
+ 'EUR': 3.0,
},
'deposit': {
'BTC': 0,
@@ -149,7 +202,9 @@ module.exports = class bitstamp extends Exchange {
'LTC': 0,
'ETH': 0,
'XRP': 0,
- 'USD': 25,
+ 'XLM': 0,
+ 'PAX': 0,
+ 'USD': 7.5,
'EUR': 0,
},
},
@@ -167,6 +222,7 @@ module.exports = class bitstamp extends Exchange {
'Please update your profile with your FATCA information, before using API.': PermissionDenied,
'Order not found': OrderNotFound,
'Price is more than 20% below market price.': InvalidOrder,
+ 'Bitstamp.net is under scheduled maintenance.': OnMaintenance, // { "error": "Bitstamp.net is under scheduled maintenance. We'll be back soon." }
},
'broad': {
'Minimum order size is': InvalidOrder, // Minimum order size is 5.0 EUR.
@@ -178,7 +234,7 @@ module.exports = class bitstamp extends Exchange {
}
async fetchMarkets (params = {}) {
- const response = await this.publicGetTradingPairsInfo (params);
+ const response = await this.fetchMarketsFromCache (params);
const result = [];
for (let i = 0; i < response.length; i++) {
const market = response[i];
@@ -229,6 +285,84 @@ module.exports = class bitstamp extends Exchange {
return result;
}
+ constructCurrencyObject (id, code, name, precision, minCost, originalPayload) {
+ let currencyType = 'crypto';
+ const description = this.describe ();
+ if (this.isFiat (code)) {
+ currencyType = 'fiat';
+ }
+ return {
+ 'id': id,
+ 'code': code,
+ 'info': originalPayload, // the original payload
+ 'type': currencyType,
+ 'name': name,
+ 'active': true,
+ 'fee': this.safeFloat (description['fees']['funding']['withdraw'], code),
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': Math.pow (10, -precision),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': Math.pow (10, -precision),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': minCost,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ };
+ }
+
+ async fetchMarketsFromCache (params = {}) {
+ // this method is now redundant
+ // currencies are now fetched before markets
+ const options = this.safeValue (this.options, 'fetchMarkets', {});
+ const timestamp = this.safeInteger (options, 'timestamp');
+ const expires = this.safeInteger (options, 'expires', 1000);
+ const now = this.milliseconds ();
+ if ((timestamp === undefined) || ((now - timestamp) > expires)) {
+ const response = await this.publicGetTradingPairsInfo (params);
+ this.options['fetchMarkets'] = this.extend (options, {
+ 'response': response,
+ 'timestamp': now,
+ });
+ }
+ return this.safeValue (this.options['fetchMarkets'], 'response');
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.fetchMarketsFromCache (params);
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ const name = this.safeString (market, 'name');
+ let [ base, quote ] = name.split ('/');
+ const baseId = base.toLowerCase ();
+ const quoteId = quote.toLowerCase ();
+ base = this.safeCurrencyCode (base);
+ quote = this.safeCurrencyCode (quote);
+ const description = this.safeString (market, 'description');
+ const [ baseDescription, quoteDescription ] = description.split (' / ');
+ const parts = market['minimum_order'].split (' ');
+ const cost = parts[0];
+ if (!(base in result)) {
+ result[base] = this.constructCurrencyObject (baseId, base, baseDescription, market['base_decimals'], undefined, market);
+ }
+ if (!(quote in result)) {
+ result[quote] = this.constructCurrencyObject (quoteId, quote, quoteDescription, market['counter_decimals'], parseFloat (cost), market);
+ }
+ }
+ return result;
+ }
+
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {
@@ -501,6 +635,16 @@ module.exports = class bitstamp extends Exchange {
};
}
+ parseTradingFee (balances, symbol) {
+ const market = this.market (symbol);
+ const tradeFee = this.safeFloat (balances, market['id'] + '_fee');
+ return {
+ 'symbol': symbol,
+ 'maker': tradeFee,
+ 'taker': tradeFee,
+ };
+ }
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -530,6 +674,71 @@ module.exports = class bitstamp extends Exchange {
return this.parseTrades (response, market, since, limit);
}
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "high": "9064.77",
+ // "timestamp": "1593961440",
+ // "volume": "18.49436608",
+ // "low": "9040.87",
+ // "close": "9064.77",
+ // "open": "9040.87"
+ // }
+ //
+ return [
+ this.safeTimestamp (ohlcv, 'timestamp'),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'volume'),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'pair': market['id'],
+ 'step': this.timeframes[timeframe],
+ };
+ const duration = this.parseTimeframe (timeframe);
+ if (limit === undefined) {
+ if (since === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument or a limit argument');
+ } else {
+ limit = 1000;
+ const start = parseInt (since / 1000);
+ request['start'] = start;
+ request['end'] = this.sum (start, limit * duration);
+ request['limit'] = limit;
+ }
+ } else {
+ if (since !== undefined) {
+ const start = parseInt (since / 1000);
+ request['start'] = start;
+ request['end'] = this.sum (start, limit * duration);
+ }
+ request['limit'] = Math.min (limit, 1000); // min 1, max 1000
+ }
+ const response = await this.publicGetOhlcPair (this.extend (request, params));
+ //
+ // {
+ // "data": {
+ // "pair": "BTC/USD",
+ // "ohlc": [
+ // {"high": "9064.77", "timestamp": "1593961440", "volume": "18.49436608", "low": "9040.87", "close": "9064.77", "open": "9040.87"},
+ // {"high": "9071.59", "timestamp": "1593961500", "volume": "3.48631711", "low": "9058.76", "close": "9061.07", "open": "9064.66"},
+ // {"high": "9067.33", "timestamp": "1593961560", "volume": "0.04142833", "low": "9061.94", "close": "9061.94", "open": "9067.33"},
+ // ],
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const ohlc = this.safeValue (data, 'ohlc', []);
+ return this.parseOHLCVs (ohlc, market, timeframe, since, limit);
+ }
+
async fetchBalance (params = {}) {
await this.loadMarkets ();
const balance = await this.privatePostBalance (params);
@@ -548,6 +757,80 @@ module.exports = class bitstamp extends Exchange {
return this.parseBalance (result);
}
+ async fetchTradingFee (symbol, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let method = 'privatePostBalance';
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['pair'] = market['id'];
+ method += 'Pair';
+ }
+ const balance = await this[method] (this.extend (request, params));
+ return {
+ 'info': balance,
+ 'symbol': symbol,
+ 'maker': balance.fee,
+ 'taker': balance.fee,
+ };
+ }
+
+ praseTradingFees (balance) {
+ const result = { 'info': balance };
+ const markets = Object.keys (this.markets);
+ for (let i = 0; i < markets.length; i++) {
+ const symbol = markets[i];
+ const fee = this.parseTradingFee (balance, symbol);
+ result[symbol] = fee;
+ }
+ return result;
+ }
+
+ async fetchTradingFees (params = {}) {
+ await this.loadMarkets ();
+ const balance = await this.privatePostBalance (params);
+ return this.praseTradingFees (balance);
+ }
+
+ parseFundingFees (balance) {
+ const withdraw = {};
+ const ids = Object.keys (balance);
+ for (let i = 0; i < ids.length; i++) {
+ const id = ids[i];
+ if (id.indexOf ('_withdrawal_fee') >= 0) {
+ const currencyId = id.split ('_')[0];
+ const code = this.safeCurrencyCode (currencyId);
+ withdraw[code] = this.safeFloat (balance, id);
+ }
+ }
+ return {
+ 'info': balance,
+ 'withdraw': withdraw,
+ 'deposit': {},
+ };
+ }
+
+ async fetchFundingFees (params = {}) {
+ await this.loadMarkets ();
+ const balance = await this.privatePostBalance (params);
+ return this.parseFundingFees (balance);
+ }
+
+ async fetchFees (params = {}) {
+ await this.loadMarkets ();
+ const balance = await this.privatePostBalance (params);
+ const tradingFees = this.praseTradingFees (balance);
+ delete tradingFees['info'];
+ const fundingFees = this.parseFundingFees (balance);
+ delete fundingFees['info'];
+ return {
+ 'info': balance,
+ 'trading': tradingFees,
+ 'funding': fundingFees,
+ };
+ }
+
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -558,6 +841,8 @@ module.exports = class bitstamp extends Exchange {
};
if (type === 'market') {
method += 'Market';
+ } else if (type === 'instant') {
+ method += 'Instant';
} else {
request['price'] = this.priceToPrecision (symbol, price);
}
@@ -687,6 +972,8 @@ module.exports = class bitstamp extends Exchange {
const request = {};
if (since !== undefined) {
request['timedelta'] = this.milliseconds () - since;
+ } else {
+ request['timedelta'] = 50000000; // use max bitstamp approved value
}
const response = await this.privatePostWithdrawalRequests (this.extend (request, params));
//
@@ -974,8 +1261,10 @@ module.exports = class bitstamp extends Exchange {
'status': status,
'symbol': symbol,
'type': undefined,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -987,6 +1276,124 @@ module.exports = class bitstamp extends Exchange {
};
}
+ parseLedgerEntryType (type) {
+ const types = {
+ '0': 'transaction',
+ '1': 'transaction',
+ '2': 'trade',
+ '14': 'transfer',
+ };
+ return this.safeString (types, type, type);
+ }
+
+ parseLedgerEntry (item, currency = undefined) {
+ //
+ // [
+ // {
+ // "fee": "0.00000000",
+ // "btc_usd": "0.00",
+ // "id": 1234567894,
+ // "usd": 0,
+ // "btc": 0,
+ // "datetime": "2018-09-08 09:00:31",
+ // "type": "1",
+ // "xrp": "-20.00000000",
+ // "eur": 0,
+ // },
+ // {
+ // "fee": "0.00000000",
+ // "btc_usd": "0.00",
+ // "id": 1134567891,
+ // "usd": 0,
+ // "btc": 0,
+ // "datetime": "2018-09-07 18:47:52",
+ // "type": "0",
+ // "xrp": "20.00000000",
+ // "eur": 0,
+ // },
+ // ]
+ //
+ const type = this.parseLedgerEntryType (this.safeString (item, 'type'));
+ if (type === 'trade') {
+ const parsedTrade = this.parseTrade (item);
+ let market = undefined;
+ const keys = Object.keys (item);
+ for (let i = 0; i < keys.length; i++) {
+ if (keys[i].indexOf ('_') >= 0) {
+ const marketId = keys[i].replace ('_', '');
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ }
+ }
+ }
+ // if the market is still not defined
+ // try to deduce it from used keys
+ if (market === undefined) {
+ market = this.getMarketFromTrade (item);
+ }
+ const direction = parsedTrade['side'] === 'buy' ? 'in' : 'out';
+ return {
+ 'id': parsedTrade['id'],
+ 'info': item,
+ 'timestamp': parsedTrade['timestamp'],
+ 'datetime': parsedTrade['datetime'],
+ 'direction': direction,
+ 'account': undefined,
+ 'referenceId': parsedTrade['order'],
+ 'referenceAccount': undefined,
+ 'type': type,
+ 'currency': market['base'],
+ 'amount': parsedTrade['amount'],
+ 'before': undefined,
+ 'after': undefined,
+ 'status': 'ok',
+ 'fee': parsedTrade['fee'],
+ };
+ } else {
+ const parsedTransaction = this.parseTransaction (item);
+ let direction = undefined;
+ if ('amount' in item) {
+ const amount = this.safeFloat (item, 'amount');
+ direction = amount > 0 ? 'in' : 'out';
+ } else if (('currency' in parsedTransaction) && parsedTransaction['currency'] !== undefined) {
+ const currencyId = this.currencyId (parsedTransaction['currency']);
+ const amount = this.safeFloat (item, currencyId);
+ direction = amount > 0 ? 'in' : 'out';
+ }
+ return {
+ 'id': parsedTransaction['id'],
+ 'info': item,
+ 'timestamp': parsedTransaction['timestamp'],
+ 'datetime': parsedTransaction['datetime'],
+ 'direction': direction,
+ 'account': undefined,
+ 'referenceId': parsedTransaction['txid'],
+ 'referenceAccount': undefined,
+ 'type': type,
+ 'currency': parsedTransaction['currency'],
+ 'amount': parsedTransaction['amount'],
+ 'before': undefined,
+ 'after': undefined,
+ 'status': parsedTransaction['status'],
+ 'fee': parsedTransaction['fee'],
+ };
+ }
+ }
+
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privatePostUserTransactions (this.extend (request, params));
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ return this.parseLedger (response, currency, since, limit);
+ }
+
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
let market = undefined;
await this.loadMarkets ();
@@ -1005,18 +1412,10 @@ module.exports = class bitstamp extends Exchange {
// }
// ]
//
- const result = [];
- for (let i = 0; i < response.length; i++) {
- const order = this.parseOrder (response[i], market);
- result.push (this.extend (order, {
- 'status': 'open',
- 'type': 'limit',
- }));
- }
- if (symbol === undefined) {
- return this.filterBySinceLimit (result, since, limit);
- }
- return this.filterBySymbolSinceLimit (result, symbol, since, limit);
+ return this.parseOrders (response, market, since, limit, {
+ 'status': 'open',
+ 'type': 'limit',
+ });
}
getCurrencyName (code) {
@@ -1027,18 +1426,12 @@ module.exports = class bitstamp extends Exchange {
}
isFiat (code) {
- if (code === 'USD') {
- return true;
- }
- if (code === 'EUR') {
- return true;
- }
- return false;
+ return code === 'USD' || code === 'EUR' || code === 'GBP';
}
async fetchDepositAddress (code, params = {}) {
if (this.isFiat (code)) {
- throw new NotSupported (this.id + ' fiat fetchDepositAddress() for ' + code + ' is not implemented yet');
+ throw new NotSupported (this.id + ' fiat fetchDepositAddress() for ' + code + ' is not supported!');
}
const name = this.getCurrencyName (code);
const v1 = (code === 'BTC');
@@ -1051,7 +1444,7 @@ module.exports = class bitstamp extends Exchange {
response = JSON.parse (response);
}
const address = v1 ? response : this.safeString (response, 'address');
- const tag = v1 ? undefined : this.safeString (response, 'destination_tag');
+ const tag = v1 ? undefined : this.safeString2 (response, 'memo_id', 'destination_tag');
this.checkAddress (address);
return {
'currency': code,
@@ -1062,22 +1455,30 @@ module.exports = class bitstamp extends Exchange {
}
async withdraw (code, amount, address, tag = undefined, params = {}) {
+ // For fiat withdrawals please provide all required additional parameters in the 'params'
+ // Check https://www.bitstamp.net/api/ under 'Open bank withdrawal' for list and description.
+ await this.loadMarkets ();
this.checkAddress (address);
- if (this.isFiat (code)) {
- throw new NotSupported (this.id + ' fiat withdraw() for ' + code + ' is not implemented yet');
- }
- const name = this.getCurrencyName (code);
const request = {
'amount': amount,
- 'address': address,
};
- const v1 = (code === 'BTC');
- let method = v1 ? 'v1' : 'private'; // v1 or v2
- method += 'Post' + this.capitalize (name) + 'Withdrawal';
- if (code === 'XRP') {
- if (tag !== undefined) {
- request['destination_tag'] = tag;
+ let method = undefined;
+ if (!this.isFiat (code)) {
+ const name = this.getCurrencyName (code);
+ const v1 = (code === 'BTC');
+ method = v1 ? 'v1' : 'private'; // v1 or v2
+ method += 'Post' + this.capitalize (name) + 'Withdrawal';
+ if (code === 'XRP') {
+ if (tag !== undefined) {
+ request['destination_tag'] = tag;
+ }
}
+ request['address'] = address;
+ } else {
+ method = 'privatePostWithdrawalOpen';
+ const currency = this.currency (code);
+ request['iban'] = address;
+ request['account_currency'] = currency['id'];
}
const response = await this[method] (this.extend (request, params));
return {
diff --git a/TaskServer/node_modules/ccxt/js/bitstamp1.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitstamp1.js
similarity index 94%
rename from TaskServer/node_modules/ccxt/js/bitstamp1.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitstamp1.js
index 8019a2435..8d8de5db1 100644
--- a/TaskServer/node_modules/ccxt/js/bitstamp1.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitstamp1.js
@@ -16,7 +16,15 @@ module.exports = class bitstamp1 extends Exchange {
'rateLimit': 1000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMyTrades': true,
+ 'fetchOrder': false,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27786377-8c8ab57e-5fe9-11e7-8ea4-2b05b6bcceec.jpg',
@@ -59,18 +67,18 @@ module.exports = class bitstamp1 extends Exchange {
},
},
'markets': {
- 'BTC/USD': { 'id': 'btcusd', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD', 'baseId': 'btc', 'quoteId': 'usd', 'maker': 0.0025, 'taker': 0.0025 },
- 'BTC/EUR': { 'id': 'btceur', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'btc', 'quoteId': 'eur', 'maker': 0.0025, 'taker': 0.0025 },
- 'EUR/USD': { 'id': 'eurusd', 'symbol': 'EUR/USD', 'base': 'EUR', 'quote': 'USD', 'baseId': 'eur', 'quoteId': 'usd', 'maker': 0.0025, 'taker': 0.0025 },
- 'XRP/USD': { 'id': 'xrpusd', 'symbol': 'XRP/USD', 'base': 'XRP', 'quote': 'USD', 'baseId': 'xrp', 'quoteId': 'usd', 'maker': 0.0025, 'taker': 0.0025 },
- 'XRP/EUR': { 'id': 'xrpeur', 'symbol': 'XRP/EUR', 'base': 'XRP', 'quote': 'EUR', 'baseId': 'xrp', 'quoteId': 'eur', 'maker': 0.0025, 'taker': 0.0025 },
- 'XRP/BTC': { 'id': 'xrpbtc', 'symbol': 'XRP/BTC', 'base': 'XRP', 'quote': 'BTC', 'baseId': 'xrp', 'quoteId': 'btc', 'maker': 0.0025, 'taker': 0.0025 },
- 'LTC/USD': { 'id': 'ltcusd', 'symbol': 'LTC/USD', 'base': 'LTC', 'quote': 'USD', 'baseId': 'ltc', 'quoteId': 'usd', 'maker': 0.0025, 'taker': 0.0025 },
- 'LTC/EUR': { 'id': 'ltceur', 'symbol': 'LTC/EUR', 'base': 'LTC', 'quote': 'EUR', 'baseId': 'ltc', 'quoteId': 'eur', 'maker': 0.0025, 'taker': 0.0025 },
- 'LTC/BTC': { 'id': 'ltcbtc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'baseId': 'ltc', 'quoteId': 'btc', 'maker': 0.0025, 'taker': 0.0025 },
- 'ETH/USD': { 'id': 'ethusd', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD', 'baseId': 'eth', 'quoteId': 'usd', 'maker': 0.0025, 'taker': 0.0025 },
- 'ETH/EUR': { 'id': 'etheur', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR', 'baseId': 'eth', 'quoteId': 'eur', 'maker': 0.0025, 'taker': 0.0025 },
- 'ETH/BTC': { 'id': 'ethbtc', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC', 'baseId': 'eth', 'quoteId': 'btc', 'maker': 0.0025, 'taker': 0.0025 },
+ 'BTC/USD': { 'id': 'btcusd', 'symbol': 'BTC/USD', 'base': 'BTC', 'quote': 'USD', 'baseId': 'btc', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
+ 'BTC/EUR': { 'id': 'btceur', 'symbol': 'BTC/EUR', 'base': 'BTC', 'quote': 'EUR', 'baseId': 'btc', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
+ 'EUR/USD': { 'id': 'eurusd', 'symbol': 'EUR/USD', 'base': 'EUR', 'quote': 'USD', 'baseId': 'eur', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
+ 'XRP/USD': { 'id': 'xrpusd', 'symbol': 'XRP/USD', 'base': 'XRP', 'quote': 'USD', 'baseId': 'xrp', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
+ 'XRP/EUR': { 'id': 'xrpeur', 'symbol': 'XRP/EUR', 'base': 'XRP', 'quote': 'EUR', 'baseId': 'xrp', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
+ 'XRP/BTC': { 'id': 'xrpbtc', 'symbol': 'XRP/BTC', 'base': 'XRP', 'quote': 'BTC', 'baseId': 'xrp', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005 },
+ 'LTC/USD': { 'id': 'ltcusd', 'symbol': 'LTC/USD', 'base': 'LTC', 'quote': 'USD', 'baseId': 'ltc', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
+ 'LTC/EUR': { 'id': 'ltceur', 'symbol': 'LTC/EUR', 'base': 'LTC', 'quote': 'EUR', 'baseId': 'ltc', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
+ 'LTC/BTC': { 'id': 'ltcbtc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'baseId': 'ltc', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005 },
+ 'ETH/USD': { 'id': 'ethusd', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD', 'baseId': 'eth', 'quoteId': 'usd', 'maker': 0.005, 'taker': 0.005 },
+ 'ETH/EUR': { 'id': 'etheur', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR', 'baseId': 'eth', 'quoteId': 'eur', 'maker': 0.005, 'taker': 0.005 },
+ 'ETH/BTC': { 'id': 'ethbtc', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC', 'baseId': 'eth', 'quoteId': 'btc', 'maker': 0.005, 'taker': 0.005 },
},
});
}
diff --git a/TaskServer/node_modules/ccxt/js/bittrex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bittrex.js
similarity index 56%
rename from TaskServer/node_modules/ccxt/js/bittrex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bittrex.js
index 1510a6c0b..36d09cbb8 100644
--- a/TaskServer/node_modules/ccxt/js/bittrex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bittrex.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { BadSymbol, ExchangeError, ExchangeNotAvailable, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound, DDoSProtection, PermissionDenied, AddressPending, OnMaintenance } = require ('./base/errors');
+const { BadSymbol, ExchangeError, ExchangeNotAvailable, AuthenticationError, InvalidOrder, InsufficientFunds, OrderNotFound, DDoSProtection, PermissionDenied, AddressPending, OnMaintenance, BadRequest } = require ('./base/errors');
const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -14,50 +14,53 @@ module.exports = class bittrex extends Exchange {
'id': 'bittrex',
'name': 'Bittrex',
'countries': [ 'US' ],
- 'version': 'v1.1',
+ 'version': 'v3',
'rateLimit': 1500,
'certified': true,
'pro': true,
// new metainfo interface
'has': {
'CORS': false,
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
'createMarketOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchDeposits': true,
'fetchDepositAddress': true,
'fetchClosedOrders': true,
'fetchCurrencies': true,
+ 'fetchMarkets': true,
'fetchMyTrades': 'emulated',
'fetchOHLCV': true,
'fetchOrder': true,
+ 'fetchOrderTrades': true,
+ 'fetchOrderBook': true,
'fetchOpenOrders': true,
+ 'fetchTicker': true,
'fetchTickers': true,
- 'withdraw': true,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTransactions': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
- '1m': 'oneMin',
- '5m': 'fiveMin',
- '30m': 'thirtyMin',
- '1h': 'hour',
- '1d': 'day',
+ '1m': 'MINUTE_1',
+ '5m': 'MINUTE_5',
+ '1h': 'HOUR_1',
+ '1d': 'DAY_1',
},
'hostname': 'bittrex.com',
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27766352-cf0b3c26-5ed5-11e7-82b7-f3826b7a97d8.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87153921-edf53180-c2c0-11ea-96b9-f2a9a95a455b.jpg',
'api': {
- 'public': 'https://{hostname}/api',
- 'account': 'https://{hostname}/api',
- 'market': 'https://{hostname}/api',
- 'v2': 'https://{hostname}/api/v2.0/pub',
- 'v3': 'https://api.bittrex.com/v3',
- 'v3public': 'https://api.bittrex.com/v3',
+ 'public': 'https://api.bittrex.com',
+ 'private': 'https://api.bittrex.com',
},
'www': 'https://bittrex.com',
'doc': [
- 'https://bittrex.github.io/api/',
'https://bittrex.github.io/api/v3',
- 'https://www.npmjs.com/package/bittrex-node',
],
'fees': [
'https://bittrex.zendesk.com/hc/en-us/articles/115003684371-BITTREX-SERVICE-FEES-AND-WITHDRAWAL-LIMITATIONS',
@@ -66,15 +69,33 @@ module.exports = class bittrex extends Exchange {
'referral': 'https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B',
},
'api': {
- 'v3': {
+ 'public': {
+ 'get': [
+ 'ping',
+ 'currencies',
+ 'currencies/{symbol}',
+ 'markets',
+ 'markets/tickers',
+ 'markets/summaries',
+ 'markets/{marketSymbol}',
+ 'markets/{marketSymbol}/summary',
+ 'markets/{marketSymbol}/orderbook',
+ 'markets/{marketSymbol}/trades',
+ 'markets/{marketSymbol}/ticker',
+ 'markets/{marketSymbol}/candles/{candleInterval}/recent',
+ 'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}/{month}/{day}',
+ 'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}/{month}',
+ 'markets/{marketSymbol}/candles/{candleInterval}/historical/{year}',
+ ],
+ },
+ 'private': {
'get': [
'account',
+ 'account/volume',
'addresses',
'addresses/{currencySymbol}',
'balances',
'balances/{currencySymbol}',
- 'currencies',
- 'currencies/{symbol}',
'deposits/open',
'deposits/closed',
'deposits/ByTxId/{txId}',
@@ -82,6 +103,7 @@ module.exports = class bittrex extends Exchange {
'orders/closed',
'orders/open',
'orders/{orderId}',
+ 'orders/{orderId}/executions',
'ping',
'subaccounts/{subaccountId}',
'subaccounts',
@@ -89,73 +111,27 @@ module.exports = class bittrex extends Exchange {
'withdrawals/closed',
'withdrawals/ByTxId/{txId}',
'withdrawals/{withdrawalId}',
+ 'withdrawals/whitelistAddresses',
+ 'conditional-orders/{conditionalOrderId}',
+ 'conditional-orders/closed',
+ 'conditional-orders/open',
+ 'transfers/sent',
+ 'transfers/received',
+ 'transfers/{transferId}',
],
'post': [
'addresses',
'orders',
'subaccounts',
'withdrawals',
+ 'conditional-orders',
+ 'transfers',
],
'delete': [
+ 'orders/open',
'orders/{orderId}',
'withdrawals/{withdrawalId}',
- ],
- },
- 'v3public': {
- 'get': [
- 'markets',
- 'markets/summaries',
- 'markets/{marketSymbol}',
- 'markets/{marketSymbol}/summary',
- 'markets/{marketSymbol}/orderbook',
- 'markets/{marketSymbol}/trades',
- 'markets/{marketSymbol}/ticker',
- 'markets/{marketSymbol}/candles',
- ],
- },
- 'v2': {
- 'get': [
- 'currencies/GetBTCPrice',
- 'currencies/GetWalletHealth',
- 'general/GetLatestAlert',
- 'market/GetTicks',
- 'market/GetLatestTick',
- 'Markets/GetMarketSummaries',
- 'market/GetLatestTick',
- ],
- },
- 'public': {
- 'get': [
- 'currencies',
- 'markethistory',
- 'markets',
- 'marketsummaries',
- 'marketsummary',
- 'orderbook',
- 'ticker',
- ],
- },
- 'account': {
- 'get': [
- 'balance',
- 'balances',
- 'depositaddress',
- 'deposithistory',
- 'order',
- 'orders',
- 'orderhistory',
- 'withdrawalhistory',
- 'withdraw',
- ],
- },
- 'market': {
- 'get': [
- 'buylimit',
- 'buymarket',
- 'cancel',
- 'openorders',
- 'selllimit',
- 'sellmarket',
+ 'conditional-orders/{conditionalOrderId}',
],
},
},
@@ -169,46 +145,12 @@ module.exports = class bittrex extends Exchange {
'funding': {
'tierBased': false,
'percentage': false,
- 'withdraw': {
- 'BTC': 0.0005,
- 'LTC': 0.01,
- 'DOGE': 2,
- 'VTC': 0.02,
- 'PPC': 0.02,
- 'FTC': 0.2,
- 'RDD': 2,
- 'NXT': 2,
- 'DASH': 0.05,
- 'POT': 0.002,
- 'BLK': 0.02,
- 'EMC2': 0.2,
- 'XMY': 0.2,
- 'GLD': 0.0002,
- 'SLR': 0.2,
- 'GRS': 0.2,
- },
- 'deposit': {
- 'BTC': 0,
- 'LTC': 0,
- 'DOGE': 0,
- 'VTC': 0,
- 'PPC': 0,
- 'FTC': 0,
- 'RDD': 0,
- 'NXT': 0,
- 'DASH': 0,
- 'POT': 0,
- 'BLK': 0,
- 'EMC2': 0,
- 'XMY': 0,
- 'GLD': 0,
- 'SLR': 0,
- 'GRS': 0,
- },
},
},
'exceptions': {
'exact': {
+ 'BAD_REQUEST': BadRequest, // {"code":"BAD_REQUEST","detail":"Refer to the data field for specific field validation failures.","data":{"invalidRequestParameter":"day"}}
+ 'STARTDATE_OUT_OF_RANGE': BadRequest, // {"code":"STARTDATE_OUT_OF_RANGE"}
// 'Call to Cancel was throttled. Try again in 60 seconds.': DDoSProtection,
// 'Call to GetBalances was throttled. Try again in 60 seconds.': DDoSProtection,
'APISIGN_NOT_PROVIDED': AuthenticationError,
@@ -237,9 +179,14 @@ module.exports = class bittrex extends Exchange {
},
},
'options': {
+ 'fetchTicker': {
+ 'method': 'publicGetMarketsMarketSymbolTicker', // publicGetMarketsMarketSymbolSummary
+ },
+ 'fetchTickers': {
+ 'method': 'publicGetMarketsTickers', // publicGetMarketsSummaries
+ },
'parseOrderStatus': false,
'hasAlreadyAuthenticatedSuccessfully': false, // a workaround for APIKEY_INVALID
- 'symbolSeparator': '-',
// With certain currencies, like
// AEON, BTS, GXS, NXT, SBD, STEEM, STR, XEM, XLM, XMR, XRP
// an additional tag / memo / payment id is usually required by exchanges.
@@ -261,12 +208,12 @@ module.exports = class bittrex extends Exchange {
},
'subaccountId': undefined,
// see the implementation of fetchClosedOrdersV3 below
- 'fetchClosedOrdersMethod': 'fetch_closed_orders_v3',
+ // 'fetchClosedOrdersMethod': 'fetch_closed_orders_v3',
'fetchClosedOrdersFilterBySince': true,
// 'createOrderMethod': 'create_order_v1',
},
'commonCurrencies': {
- 'BITS': 'SWIFT',
+ 'REPV2': 'REP',
},
});
}
@@ -280,7 +227,7 @@ module.exports = class bittrex extends Exchange {
}
async fetchMarkets (params = {}) {
- const response = await this.v3publicGetMarkets (params);
+ const response = await this.publicGetMarkets (params);
//
// [
// {
@@ -305,17 +252,11 @@ module.exports = class bittrex extends Exchange {
// ]
//
const result = [];
- // const markets = this.safeValue (response, 'result');
for (let i = 0; i < response.length; i++) {
const market = response[i];
const baseId = this.safeString (market, 'baseCurrencySymbol');
const quoteId = this.safeString (market, 'quoteCurrencySymbol');
- // bittrex v2 uses inverted pairs, v3 uses regular pairs
- // we use v3 for fetchMarkets and v2 throughout the rest of this implementation
- // therefore we swap the base ←→ quote here to be v2-compatible
- // https://github.com/ccxt/ccxt/issues/5634
- // const id = this.safeString (market, 'symbol');
- const id = quoteId + this.options['symbolSeparator'] + baseId;
+ const id = this.safeString (market, 'symbol');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
@@ -342,7 +283,11 @@ module.exports = class bittrex extends Exchange {
'max': undefined,
},
'price': {
- 'min': Math.pow (10, -precision['price']),
+ 'min': 1 / Math.pow (10, precision['price']),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
'max': undefined,
},
},
@@ -353,18 +298,17 @@ module.exports = class bittrex extends Exchange {
async fetchBalance (params = {}) {
await this.loadMarkets ();
- const response = await this.accountGetBalances (params);
- const balances = this.safeValue (response, 'result');
+ const balances = await this.privateGetBalances (params);
const result = { 'info': balances };
- const indexed = this.indexBy (balances, 'Currency');
+ const indexed = this.indexBy (balances, 'currencySymbol');
const currencyIds = Object.keys (indexed);
for (let i = 0; i < currencyIds.length; i++) {
const currencyId = currencyIds[i];
const code = this.safeCurrencyCode (currencyId);
const account = this.account ();
const balance = indexed[currencyId];
- account['free'] = this.safeFloat (balance, 'Available');
- account['total'] = this.safeFloat (balance, 'Balance');
+ account['free'] = this.safeFloat (balance, 'available');
+ account['total'] = this.safeFloat (balance, 'total');
result[code] = account;
}
return this.parseBalance (result);
@@ -373,75 +317,79 @@ module.exports = class bittrex extends Exchange {
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {
- 'market': this.marketId (symbol),
- 'type': 'both',
+ 'marketSymbol': this.marketId (symbol),
};
- const response = await this.publicGetOrderbook (this.extend (request, params));
- let orderbook = response['result'];
- if ('type' in params) {
- if (params['type'] === 'buy') {
- orderbook = {
- 'buy': response['result'],
- 'sell': [],
- };
- } else if (params['type'] === 'sell') {
- orderbook = {
- 'buy': [],
- 'sell': response['result'],
- };
+ if (limit !== undefined) {
+ if ((limit !== 1) && (limit !== 25) && (limit !== 500)) {
+ throw new BadRequest (this.id + ' fetchOrderBook() limit argument must be undefined, 1, 25 or 500, default is 25');
}
+ request['depth'] = limit;
}
- return this.parseOrderBook (orderbook, undefined, 'buy', 'sell', 'Rate', 'Quantity');
+ const response = await this.publicGetMarketsMarketSymbolOrderbook (this.extend (request, params));
+ //
+ // {
+ // "bid":[
+ // {"quantity":"0.01250000","rate":"10718.56200003"},
+ // {"quantity":"0.10000000","rate":"10718.56200002"},
+ // {"quantity":"0.39648292","rate":"10718.56200001"},
+ // ],
+ // "ask":[
+ // {"quantity":"0.05100000","rate":"10724.30099631"},
+ // {"quantity":"0.10000000","rate":"10724.30099632"},
+ // {"quantity":"0.26000000","rate":"10724.30099634"},
+ // ]
+ // }
+ //
+ const sequence = this.safeInteger (this.last_response_headers, 'Sequence');
+ const orderbook = this.parseOrderBook (response, undefined, 'bid', 'ask', 'rate', 'quantity');
+ orderbook['nonce'] = sequence;
+ return orderbook;
}
async fetchCurrencies (params = {}) {
const response = await this.publicGetCurrencies (params);
//
- // {
- // "success": true,
- // "message": "",
- // "result": [
- // {
- // "Currency": "BTC",
- // "CurrencyLong":"Bitcoin",
- // "MinConfirmation":2,
- // "TxFee":0.00050000,
- // "IsActive":true,
- // "IsRestricted":false,
- // "CoinType":"BITCOIN",
- // "BaseAddress":"1N52wHoVR79PMDishab2XmRHsbekCdGquK",
- // "Notice":null
- // },
- // ...,
- // ]
- // }
+ // [
+ // {
+ // "symbol":"1ST",
+ // "name":"Firstblood",
+ // "coinType":"ETH_CONTRACT",
+ // "status":"ONLINE",
+ // "minConfirmations":36,
+ // "notice":"",
+ // "txFee":"4.50000000",
+ // "logoUrl":"https://bittrexblobstorage.blob.core.windows.net/public/5685a7be-1edf-4ba0-a313-b5309bb204f8.png",
+ // "prohibitedIn":[],
+ // "baseAddress":"0xfbb1b73c4f0bda4f67dca266ce6ef42f520fbb98",
+ // "associatedTermsOfService":[]
+ // }
+ // ]
//
- const currencies = this.safeValue (response, 'result', []);
const result = {};
- for (let i = 0; i < currencies.length; i++) {
- const currency = currencies[i];
- const id = this.safeString (currency, 'Currency');
+ for (let i = 0; i < response.length; i++) {
+ const currency = response[i];
+ const id = this.safeString (currency, 'symbol');
const code = this.safeCurrencyCode (id);
const precision = 8; // default precision, todo: fix "magic constants"
- const address = this.safeValue (currency, 'BaseAddress');
- const fee = this.safeFloat (currency, 'TxFee'); // todo: redesign
+ const fee = this.safeFloat (currency, 'txFee'); // todo: redesign
+ const isActive = this.safeString (currency, 'status');
result[code] = {
'id': id,
'code': code,
- 'address': address,
+ 'address': this.safeString (currency, 'baseAddress'),
'info': currency,
- 'type': this.safeString (currency, 'CoinType'),
- 'name': this.safeString (currency, 'CurrencyLong'),
- 'active': this.safeValue (currency, 'IsActive'),
+ 'type': this.safeString (currency, 'coinType'),
+ 'name': this.safeString (currency, 'name'),
+ 'active': (isActive === 'ONLINE'),
'fee': fee,
'precision': precision,
'limits': {
'amount': {
- 'min': Math.pow (10, -precision),
+ 'min': 1 / Math.pow (10, precision),
'max': undefined,
},
'price': {
- 'min': Math.pow (10, -precision),
+ 'min': 1 / Math.pow (10, precision),
'max': undefined,
},
'cost': {
@@ -459,79 +407,93 @@ module.exports = class bittrex extends Exchange {
}
parseTicker (ticker, market = undefined) {
+ //
+ // ticker
//
// {
- // "MarketName":"BTC-ETH",
- // "High":0.02127099,
- // "Low":0.02035064,
- // "Volume":10288.40271571,
- // "Last":0.02070510,
- // "BaseVolume":214.64663206,
- // "TimeStamp":"2019-09-18T21:03:59.897",
- // "Bid":0.02070509,
- // "Ask":0.02070510,
- // "OpenBuyOrders":1228,
- // "OpenSellOrders":5899,
- // "PrevDay":0.02082823,
- // "Created":"2015-08-14T09:02:24.817"
+ // "symbol":"ETH-BTC",
+ // "lastTradeRate":"0.03284496",
+ // "bidRate":"0.03284523",
+ // "askRate":"0.03286857"
// }
//
- const timestamp = this.parse8601 (this.safeString (ticker, 'TimeStamp'));
- let symbol = undefined;
- const marketId = this.safeString (ticker, 'MarketName');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- symbol = this.parseSymbol (marketId);
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
- const previous = this.safeFloat (ticker, 'PrevDay');
- const last = this.safeFloat (ticker, 'Last');
- let change = undefined;
- let percentage = undefined;
- if (last !== undefined) {
- if (previous !== undefined) {
- change = last - previous;
- if (previous > 0) {
- percentage = (change / previous) * 100;
- }
- }
- }
+ // summary
+ //
+ // {
+ // "symbol":"ETH-BTC",
+ // "high":"0.03369528",
+ // "low":"0.03282442",
+ // "volume":"4307.83794556",
+ // "quoteVolume":"143.08608869",
+ // "percentChange":"0.79",
+ // "updatedAt":"2020-09-29T07:36:57.823Z"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (ticker, 'updatedAt'));
+ const marketId = this.safeString (ticker, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const percentage = this.safeFloat (ticker, 'percentChange');
+ const last = this.safeFloat (ticker, 'lastTradeRate');
return {
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'high': this.safeFloat (ticker, 'High'),
- 'low': this.safeFloat (ticker, 'Low'),
- 'bid': this.safeFloat (ticker, 'Bid'),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': this.safeFloat (ticker, 'bidRate'),
'bidVolume': undefined,
- 'ask': this.safeFloat (ticker, 'Ask'),
+ 'ask': this.safeFloat (ticker, 'askRate'),
'askVolume': undefined,
'vwap': undefined,
- 'open': previous,
+ 'open': undefined,
'close': last,
'last': last,
'previousClose': undefined,
- 'change': change,
+ 'change': undefined,
'percentage': percentage,
'average': undefined,
- 'baseVolume': this.safeFloat (ticker, 'Volume'),
- 'quoteVolume': this.safeFloat (ticker, 'BaseVolume'),
+ 'baseVolume': this.safeFloat (ticker, 'volume'),
+ 'quoteVolume': this.safeFloat (ticker, 'quoteVolume'),
'info': ticker,
};
}
async fetchTickers (symbols = undefined, params = {}) {
await this.loadMarkets ();
- const response = await this.publicGetMarketsummaries (params);
- const result = this.safeValue (response, 'result');
+ const options = this.safeValue (this.options, 'fetchTickers', {});
+ const defaultMethod = this.safeString (options, 'method', 'publicGetMarketsTickers');
+ const method = this.safeString (params, 'method', defaultMethod);
+ params = this.omit (params, 'method');
+ const response = await this[method] (params);
+ //
+ // publicGetMarketsTickers
+ //
+ // [
+ // {
+ // "symbol":"4ART-BTC",
+ // "lastTradeRate":"0.00000210",
+ // "bidRate":"0.00000210",
+ // "askRate":"0.00000215"
+ // }
+ // ]
+ //
+ // publicGetMarketsSummaries
+ //
+ // [
+ // {
+ // "symbol":"4ART-BTC",
+ // "high":"0.00000206",
+ // "low":"0.00000196",
+ // "volume":"14871.32000233",
+ // "quoteVolume":"0.02932756",
+ // "percentChange":"1.48",
+ // "updatedAt":"2020-09-29T07:34:32.757Z"
+ // }
+ // ]
+ //
const tickers = [];
- for (let i = 0; i < result.length; i++) {
- const ticker = this.parseTicker (result[i]);
+ for (let i = 0; i < response.length; i++) {
+ const ticker = this.parseTicker (response[i]);
tickers.push (ticker);
}
return this.filterByArray (tickers, 'symbol', symbols);
@@ -541,114 +503,211 @@ module.exports = class bittrex extends Exchange {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
- 'market': market['id'],
+ 'marketSymbol': market['id'],
};
- const response = await this.publicGetMarketsummary (this.extend (request, params));
+ const options = this.safeValue (this.options, 'fetchTicker', {});
+ const defaultMethod = this.safeString (options, 'method', 'publicGetMarketsMarketSymbolTicker');
+ const method = this.safeString (params, 'method', defaultMethod);
+ params = this.omit (params, 'method');
+ const response = await this[method] (this.extend (request, params));
+ //
+ // publicGetMarketsMarketSymbolTicker
//
// {
- // "success":true,
- // "message":"",
- // "result":[
- // {
- // "MarketName":"BTC-ETH",
- // "High":0.02127099,
- // "Low":0.02035064,
- // "Volume":10288.40271571,
- // "Last":0.02070510,
- // "BaseVolume":214.64663206,
- // "TimeStamp":"2019-09-18T21:03:59.897",
- // "Bid":0.02070509,
- // "Ask":0.02070510,
- // "OpenBuyOrders":1228,
- // "OpenSellOrders":5899,
- // "PrevDay":0.02082823,
- // "Created":"2015-08-14T09:02:24.817"
- // }
- // ]
+ // "symbol":"ETH-BTC",
+ // "lastTradeRate":"0.03284496",
+ // "bidRate":"0.03284523",
+ // "askRate":"0.03286857"
// }
//
- const ticker = response['result'][0];
- return this.parseTicker (ticker, market);
+ //
+ // publicGetMarketsMarketSymbolSummary
+ //
+ // {
+ // "symbol":"ETH-BTC",
+ // "high":"0.03369528",
+ // "low":"0.03282442",
+ // "volume":"4307.83794556",
+ // "quoteVolume":"143.08608869",
+ // "percentChange":"0.79",
+ // "updatedAt":"2020-09-29T07:36:57.823Z"
+ // }
+ //
+ return this.parseTicker (response, market);
}
parseTrade (trade, market = undefined) {
- const timestamp = this.parse8601 (trade['TimeStamp'] + '+00:00');
- let side = undefined;
- if (trade['OrderType'] === 'BUY') {
- side = 'buy';
- } else if (trade['OrderType'] === 'SELL') {
- side = 'sell';
- }
- const id = this.safeString2 (trade, 'Id', 'ID');
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ //
+ // public fetchTrades
+ //
+ // {
+ // "id":"9c5589db-42fb-436c-b105-5e2edcb95673",
+ // "executedAt":"2020-10-03T11:48:43.38Z",
+ // "quantity":"0.17939626",
+ // "rate":"0.03297952",
+ // "takerSide":"BUY"
+ // }
+ //
+ // private fetchOrderTrades
+ //
+ // {
+ // "id": "aaa3e9bd-5b86-4a21-8b3d-1275c1d30b8e",
+ // "marketSymbol": "OMG-BTC",
+ // "executedAt": "2020-10-02T16:00:30.3Z",
+ // "quantity": "7.52710000",
+ // "rate": "0.00034907",
+ // "orderId": "3a3dbd33-3a30-4ae5-a41d-68d3c1ac537e",
+ // "commission": "0.00000525",
+ // "isTaker": false
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (trade, 'executedAt'));
+ const id = this.safeString (trade, 'id');
+ const order = this.safeString (trade, 'orderId');
+ const marketId = this.safeString (trade, 'marketSymbol');
+ market = this.safeMarket (marketId, market, '-');
let cost = undefined;
- const price = this.safeFloat (trade, 'Price');
- const amount = this.safeFloat (trade, 'Quantity');
+ const price = this.safeFloat (trade, 'rate');
+ const amount = this.safeFloat (trade, 'quantity');
if (amount !== undefined) {
if (price !== undefined) {
cost = price * amount;
}
}
+ let takerOrMaker = undefined;
+ const isTaker = this.safeValue (trade, 'isTaker');
+ if (isTaker !== undefined) {
+ takerOrMaker = isTaker ? 'taker' : 'maker';
+ }
+ let fee = undefined;
+ const feeCost = this.safeFloat (trade, 'commission');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': market['quote'],
+ };
+ }
+ const side = this.safeStringLower (trade, 'takerSide');
return {
'info': trade,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'id': id,
- 'order': undefined,
- 'type': 'limit',
- 'takerOrMaker': undefined,
+ 'order': order,
+ 'takerOrMaker': takerOrMaker,
+ 'type': undefined,
'side': side,
'price': price,
'amount': amount,
'cost': cost,
- 'fee': undefined,
+ 'fee': fee,
};
}
+ async fetchTime (params = {}) {
+ const response = await this.publicGetPing (params);
+ //
+ // {
+ // "serverTime": 1594596023162
+ // }
+ //
+ return this.safeInteger (response, 'serverTime');
+ }
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
- 'market': market['id'],
+ 'marketSymbol': this.marketId (symbol),
};
- const response = await this.publicGetMarkethistory (this.extend (request, params));
- if ('result' in response) {
- if (response['result'] !== undefined) {
- return this.parseTrades (response['result'], market, since, limit);
- }
- }
- throw new ExchangeError (this.id + ' fetchTrades() returned undefined response');
+ const response = await this.publicGetMarketsMarketSymbolTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id":"9c5589db-42fb-436c-b105-5e2edcb95673",
+ // "executedAt":"2020-10-03T11:48:43.38Z",
+ // "quantity":"0.17939626",
+ // "rate":"0.03297952",
+ // "takerSide":"BUY"
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
- const timestamp = this.parse8601 (ohlcv['T'] + '+00:00');
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "startsAt":"2020-06-12T02:35:00Z",
+ // "open":"0.02493753",
+ // "high":"0.02493753",
+ // "low":"0.02493753",
+ // "close":"0.02493753",
+ // "volume":"0.09590123",
+ // "quoteVolume":"0.00239153"
+ // }
+ //
return [
- timestamp,
- ohlcv['O'],
- ohlcv['H'],
- ohlcv['L'],
- ohlcv['C'],
- ohlcv['V'],
+ this.parse8601 (this.safeString (ohlcv, 'startsAt')),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'volume'),
];
}
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
+ const reverseId = market['baseId'] + '-' + market['quoteId'];
const request = {
- 'tickInterval': this.timeframes[timeframe],
- 'marketName': market['id'],
+ 'candleInterval': this.timeframes[timeframe],
+ 'marketSymbol': reverseId,
};
- const response = await this.v2GetMarketGetTicks (this.extend (request, params));
- if ('result' in response) {
- if (response['result']) {
- return this.parseOHLCVs (response['result'], market, timeframe, since, limit);
+ let method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalRecent';
+ if (since !== undefined) {
+ const now = this.milliseconds ();
+ const difference = Math.abs (now - since);
+ const sinceDate = this.ymd (since);
+ const parts = sinceDate.split ('-');
+ const sinceYear = this.safeInteger (parts, 0);
+ const sinceMonth = this.safeInteger (parts, 1);
+ const sinceDay = this.safeInteger (parts, 2);
+ if (timeframe === '1d') {
+ // if the since argument is beyond one year into the past
+ if (difference > 31622400000) {
+ method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYear';
+ request['year'] = sinceYear;
+ }
+ // request['year'] = year;
+ } else if (timeframe === '1h') {
+ // if the since argument is beyond 31 days into the past
+ if (difference > 2678400000) {
+ method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYearMonth';
+ request['year'] = sinceYear;
+ request['month'] = sinceMonth;
+ }
+ } else {
+ // if the since argument is beyond 1 day into the past
+ if (difference > 86400000) {
+ method = 'publicGetMarketsMarketSymbolCandlesCandleIntervalHistoricalYearMonthDay';
+ request['year'] = sinceYear;
+ request['month'] = sinceMonth;
+ request['day'] = sinceDay;
+ }
}
}
+ const response = await this[method] (this.extend (request, params));
+ //
+ // [
+ // {"startsAt":"2020-06-12T02:35:00Z","open":"0.02493753","high":"0.02493753","low":"0.02493753","close":"0.02493753","volume":"0.09590123","quoteVolume":"0.00239153"},
+ // {"startsAt":"2020-06-12T02:40:00Z","open":"0.02491874","high":"0.02491874","low":"0.02490970","close":"0.02490970","volume":"0.04515695","quoteVolume":"0.00112505"},
+ // {"startsAt":"2020-06-12T02:45:00Z","open":"0.02490753","high":"0.02493143","low":"0.02490753","close":"0.02493143","volume":"0.17769640","quoteVolume":"0.00442663"}
+ // ]
+ //
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -657,26 +716,26 @@ module.exports = class bittrex extends Exchange {
let market = undefined;
if (symbol !== undefined) {
market = this.market (symbol);
- request['market'] = market['id'];
+ request['marketSymbol'] = market['id'];
}
- const response = await this.marketGetOpenorders (this.extend (request, params));
- const result = this.safeValue (response, 'result', []);
- const orders = this.parseOrders (result, market, since, limit);
- return this.filterBySymbol (orders, symbol);
+ const response = await this.privateGetOrdersOpen (this.extend (request, params));
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'orderId': id,
+ };
+ const response = await this.privateGetOrdersOrderIdExecutions (this.extend (request, params));
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ return this.parseTrades (response, market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
- const uppercaseType = type.toUpperCase ();
- const isMarket = (uppercaseType === 'MARKET');
- const isCeilingLimit = (uppercaseType === 'CEILING_LIMIT');
- const isCeilingMarket = (uppercaseType === 'CEILING_MARKET');
- const isV3 = isMarket || isCeilingLimit || isCeilingMarket;
- const defaultMethod = isV3 ? 'create_order_v3' : 'create_order_v1';
- const method = this.safeValue (this.options, 'createOrderMethod', defaultMethod);
- return await this[method] (symbol, type, side, amount, price, params);
- }
-
- async createOrderV3 (symbol, type, side, amount, price = undefined, params = {}) {
// A ceiling order is a market or limit order that allows you to specify
// the amount of quote currency you want to spend (or receive, if selling)
// instead of the quantity of the market currency (e.g. buy $100 USD of BTC
@@ -712,7 +771,7 @@ module.exports = class bittrex extends Exchange {
request['timeInForce'] = 'IMMEDIATE_OR_CANCEL';
}
}
- const response = await this.v3PostOrders (this.extend (request, params));
+ const response = await this.privatePostOrders (this.extend (request, params));
//
// {
// id: 'f03d5e98-b5ac-48fb-8647-dd4db828a297',
@@ -730,63 +789,63 @@ module.exports = class bittrex extends Exchange {
// updatedAt: '2020-03-18T02:37:33.42Z'
// }
//
- return this.parseOrderV3 (response, market);
- }
-
- async createOrderV1 (symbol, type, side, amount, price = undefined, params = {}) {
- if (type !== 'limit') {
- throw new ExchangeError (this.id + ' allows limit orders only');
- }
- await this.loadMarkets ();
- const market = this.market (symbol);
- const method = 'marketGet' + this.capitalize (side) + type;
- const request = {
- 'market': market['id'],
- 'quantity': this.amountToPrecision (symbol, amount),
- 'rate': this.priceToPrecision (symbol, price),
- };
- // if (type == 'limit')
- // order['rate'] = this.priceToPrecision (symbol, price);
- const response = await this[method] (this.extend (request, params));
- const orderIdField = this.getOrderIdField ();
- const orderId = this.safeString (response['result'], orderIdField);
- return {
- 'info': response,
- 'id': orderId,
- 'symbol': symbol,
- 'type': type,
- 'side': side,
- 'status': 'open',
- };
- }
-
- getOrderIdField () {
- return 'uuid';
+ return this.parseOrder (response, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- const orderIdField = this.getOrderIdField ();
- const request = {};
- request[orderIdField] = id;
- const response = await this.marketGetCancel (this.extend (request, params));
- //
- // {
- // "success": true,
- // "message": "''",
- // "result": {
- // "uuid": "614c34e4-8d71-11e3-94b5-425861b86ab6"
- // }
- // }
- //
- const result = this.safeValue (response, 'result', {});
- return this.extend (this.parseOrder (result), {
+ const request = {
+ 'orderId': id,
+ };
+ const response = await this.privateDeleteOrdersOrderId (this.extend (request, params));
+ return this.extend (this.parseOrder (response), {
'id': id,
'info': response,
'status': 'canceled',
});
}
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['marketSymbol'] = market['id'];
+ }
+ const response = await this.privateDeleteOrdersOpen (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id":"66582be0-5337-4d8c-b212-c356dd525801",
+ // "statusCode":"SUCCESS",
+ // "result":{
+ // "id":"66582be0-5337-4d8c-b212-c356dd525801",
+ // "marketSymbol":"BTC-USDT",
+ // "direction":"BUY",
+ // "type":"LIMIT",
+ // "quantity":"0.01000000",
+ // "limit":"3000.00000000",
+ // "timeInForce":"GOOD_TIL_CANCELLED",
+ // "fillQuantity":"0.00000000",
+ // "commission":"0.00000000",
+ // "proceeds":"0.00000000",
+ // "status":"CLOSED",
+ // "createdAt":"2020-10-06T12:31:53.39Z",
+ // "updatedAt":"2020-10-06T12:54:28.8Z",
+ // "closedAt":"2020-10-06T12:54:28.8Z"
+ // }
+ // }
+ // ]
+ //
+ const orders = [];
+ for (let i = 0; i < response.length; i++) {
+ const result = this.safeValue (response[i], 'result', {});
+ orders.push (result);
+ }
+ return this.parseOrders (orders, market);
+ }
+
async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
// https://support.bittrex.com/hc/en-us/articles/115003723911
@@ -794,24 +853,13 @@ module.exports = class bittrex extends Exchange {
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
- request['currency'] = currency['id'];
+ request['currencySymbol'] = currency['id'];
}
- const response = await this.accountGetDeposithistory (this.extend (request, params));
- //
- // { success: true,
- // message: "",
- // result: [ { Id: 22578097,
- // Amount: 0.3,
- // Currency: "ETH",
- // Confirmations: 15,
- // LastUpdated: "2018-06-10T07:12:10.57",
- // TxId: "0xf50b5ba2ca5438b58f93516eaa523eaf35b4420ca0f24061003df1be7…",
- // CryptoAddress: "0xb25f281fa51f1635abd4a60b0870a62d2a7fa404" } ] }
- //
+ const response = await this.privateGetDepositsClosed (this.extend (request, params));
// we cannot filter by `since` timestamp, as it isn't set by Bittrex
// see https://github.com/ccxt/ccxt/issues/4067
- // return this.parseTransactions (response['result'], currency, since, limit);
- return this.parseTransactions (response['result'], currency, undefined, limit);
+ // return this.parseTransactions (response, currency, since, limit);
+ return this.parseTransactions (response, currency, undefined, limit);
}
async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
@@ -821,60 +869,29 @@ module.exports = class bittrex extends Exchange {
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
- request['currency'] = currency['id'];
+ request['currencySymbol'] = currency['id'];
}
- const response = await this.accountGetWithdrawalhistory (this.extend (request, params));
- //
- // {
- // "success" : true,
- // "message" : "",
- // "result" : [{
- // "PaymentUuid" : "b32c7a5c-90c6-4c6e-835c-e16df12708b1",
- // "Currency" : "BTC",
- // "Amount" : 17.00000000,
- // "Address" : "1DfaaFBdbB5nrHj87x3NHS4onvw1GPNyAu",
- // "Opened" : "2014-07-09T04:24:47.217",
- // "Authorized" : true,
- // "PendingPayment" : false,
- // "TxCost" : 0.00020000,
- // "TxId" : null,
- // "Canceled" : true,
- // "InvalidAddress" : false
- // }, {
- // "PaymentUuid" : "d193da98-788c-4188-a8f9-8ec2c33fdfcf",
- // "Currency" : "XC",
- // "Amount" : 7513.75121715,
- // "Address" : "TcnSMgAd7EonF2Dgc4c9K14L12RBaW5S5J",
- // "Opened" : "2014-07-08T23:13:31.83",
- // "Authorized" : true,
- // "PendingPayment" : false,
- // "TxCost" : 0.00002000,
- // "TxId" : "d8a575c2a71c7e56d02ab8e26bb1ef0a2f6cf2094f6ca2116476a569c1e84f6e",
- // "Canceled" : false,
- // "InvalidAddress" : false
- // }
- // ]
- // }
- //
- return this.parseTransactions (response['result'], currency, since, limit);
+ const response = await this.privateGetWithdrawalsClosed (this.extend (request, params));
+ return this.parseTransactions (response, currency, since, limit);
}
parseTransaction (transaction, currency = undefined) {
//
// fetchDeposits
- //
// {
- // Id: 72578097,
- // Amount: 0.3,
- // Currency: "ETH",
- // Confirmations: 15,
- // LastUpdated: "2018-06-17T07:12:14.57",
- // TxId: "0xb31b5ba2ca5438b58f93516eaa523eaf35b4420ca0f24061003df1be7…",
- // CryptoAddress: "0x2d5f281fa51f1635abd4a60b0870a62d2a7fa404"
+ // "id": "d00fdf2e-df9e-48f1-....",
+ // "currencySymbol": "BTC",
+ // "quantity": "0.00550000",
+ // "cryptoAddress": "1PhmYjnJPZH5NUwV8AU...",
+ // "txId": "d1f1afffe1b9b6614eaee7e8133c85d98...",
+ // "confirmations": 2,
+ // "updatedAt": "2020-01-12T16:49:30.41Z",
+ // "completedAt": "2020-01-12T16:49:30.41Z",
+ // "status": "COMPLETED",
+ // "source": "BLOCKCHAIN"
// }
//
// fetchWithdrawals
- //
// {
// "PaymentUuid" : "e293da98-788c-4188-a8f9-8ec2c33fdfcf",
// "Currency" : "XC",
@@ -889,15 +906,15 @@ module.exports = class bittrex extends Exchange {
// "InvalidAddress" : false
// }
//
- const id = this.safeString2 (transaction, 'Id', 'PaymentUuid');
- const amount = this.safeFloat (transaction, 'Amount');
- const address = this.safeString2 (transaction, 'CryptoAddress', 'Address');
- const txid = this.safeString (transaction, 'TxId');
- const updated = this.parse8601 (this.safeString (transaction, 'LastUpdated'));
- const opened = this.parse8601 (this.safeString (transaction, 'Opened'));
+ const id = this.safeString (transaction, 'id');
+ const amount = this.safeFloat (transaction, 'quantity');
+ const address = this.safeString (transaction, 'cryptoAddress');
+ const txid = this.safeString (transaction, 'txId');
+ const updated = this.parse8601 (this.safeString (transaction, 'updatedAt'));
+ const opened = this.parse8601 (this.safeString (transaction, 'createdAt'));
const timestamp = opened ? opened : updated;
const type = (opened === undefined) ? 'deposit' : 'withdrawal';
- const currencyId = this.safeString (transaction, 'Currency');
+ const currencyId = this.safeString (transaction, 'currencySymbol');
const code = this.safeCurrencyCode (currencyId, currency);
let status = 'pending';
if (type === 'deposit') {
@@ -913,25 +930,24 @@ module.exports = class bittrex extends Exchange {
//
status = 'ok';
} else {
- const authorized = this.safeValue (transaction, 'Authorized', false);
- const pendingPayment = this.safeValue (transaction, 'PendingPayment', false);
- const canceled = this.safeValue (transaction, 'Canceled', false);
- const invalidAddress = this.safeValue (transaction, 'InvalidAddress', false);
- if (invalidAddress) {
+ const responseStatus = this.safeString (transaction, 'status');
+ if (responseStatus === 'ERROR_INVALID_ADDRESS') {
status = 'failed';
- } else if (canceled) {
+ } else if (responseStatus === 'CANCELLED') {
status = 'canceled';
- } else if (pendingPayment) {
+ } else if (responseStatus === 'PENDING') {
status = 'pending';
- } else if (authorized && (txid !== undefined)) {
+ } else if (responseStatus === 'COMPLETED') {
+ status = 'ok';
+ } else if (responseStatus === 'AUTHORIZED' && (txid !== undefined)) {
status = 'ok';
}
}
- let feeCost = this.safeFloat (transaction, 'TxCost');
+ let feeCost = this.safeFloat (transaction, 'txCost');
if (feeCost === undefined) {
if (type === 'deposit') {
// according to https://support.bittrex.com/hc/en-us/articles/115000199651-What-fees-does-Bittrex-charge-
- feeCost = 0; // FIXME: remove hardcoded value that may change any time
+ feeCost = 0;
}
}
return {
@@ -954,40 +970,17 @@ module.exports = class bittrex extends Exchange {
};
}
- parseSymbol (id) {
- const [ quoteId, baseId ] = id.split (this.options['symbolSeparator']);
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- return base + '/' + quote;
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'GOOD_TIL_CANCELLED': 'GTC',
+ 'IMMEDIATE_OR_CANCEL': 'IOC',
+ 'FILL_OR_KILL': 'FOK',
+ 'POST_ONLY_GOOD_TIL_CANCELLED': 'POST_ONLY_GOOD_TIL_CANCELLED',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
}
parseOrder (order, market = undefined) {
- if ('marketSymbol' in order) {
- return this.parseOrderV3 (order, market);
- } else {
- return this.parseOrderV2 (order, market);
- }
- }
-
- parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
- if (this.options['fetchClosedOrdersFilterBySince']) {
- return super.parseOrders (orders, market, since, limit, params);
- } else {
- return super.parseOrders (orders, market, undefined, limit, params);
- }
- }
-
- parseOrderStatus (status) {
- const statuses = {
- 'CLOSED': 'closed',
- 'OPEN': 'open',
- 'CANCELLED': 'canceled',
- 'CANCELED': 'canceled',
- };
- return this.safeString (statuses, status, status);
- }
-
- parseOrderV3 (order, market = undefined) {
//
// {
// id: '1be35109-b763-44ce-b6ea-05b6b0735c0c',
@@ -1033,7 +1026,6 @@ module.exports = class bittrex extends Exchange {
const fillQuantity = this.safeFloat (order, 'fillQuantity');
const commission = this.safeFloat (order, 'commission');
const proceeds = this.safeFloat (order, 'proceeds');
- const status = this.safeStringLower (order, 'status');
let average = undefined;
let remaining = undefined;
if (fillQuantity !== undefined) {
@@ -1048,6 +1040,11 @@ module.exports = class bittrex extends Exchange {
remaining = quantity - fillQuantity;
}
}
+ let status = this.safeStringLower (order, 'status');
+ if ((status === 'closed') && (remaining !== undefined) && (remaining > 0)) {
+ status = 'canceled';
+ }
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'timeInForce'));
return {
'id': this.safeString (order, 'id'),
'clientOrderId': undefined,
@@ -1056,8 +1053,10 @@ module.exports = class bittrex extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': direction,
'price': limit,
+ 'stopPrice': undefined,
'cost': proceeds,
'average': average,
'amount': quantity,
@@ -1073,154 +1072,32 @@ module.exports = class bittrex extends Exchange {
};
}
- parseOrderV2 (order, market = undefined) {
- //
- // {
- // "Uuid": "string (uuid)",
- // "OrderUuid": "8925d746-bc9f-4684-b1aa-e507467aaa99",
- // "Exchange": "BTC-LTC",
- // "OrderType": "string",
- // "Quantity": 100000,
- // "QuantityRemaining": 100000,
- // "Limit": 1e-8,
- // "CommissionPaid": 0,
- // "Price": 0,
- // "PricePerUnit": null,
- // "Opened": "2014-07-09T03:55:48.583",
- // "Closed": null,
- // "CancelInitiated": "boolean",
- // "ImmediateOrCancel": "boolean",
- // "IsConditional": "boolean"
- // }
- //
- let side = this.safeString2 (order, 'OrderType', 'Type');
- const isBuyOrder = (side === 'LIMIT_BUY') || (side === 'BUY');
- const isSellOrder = (side === 'LIMIT_SELL') || (side === 'SELL');
- if (isBuyOrder) {
- side = 'buy';
- }
- if (isSellOrder) {
- side = 'sell';
- }
- // We parse different fields in a very specific order.
- // Order might well be closed and then canceled.
- let status = undefined;
- if (('Opened' in order) && order['Opened']) {
- status = 'open';
- }
- if (('Closed' in order) && order['Closed']) {
- status = 'closed';
- }
- if (('CancelInitiated' in order) && order['CancelInitiated']) {
- status = 'canceled';
- }
- if (('Status' in order) && this.options['parseOrderStatus']) {
- status = this.parseOrderStatus (this.safeString (order, 'Status'));
- }
- let symbol = undefined;
- if ('Exchange' in order) {
- const marketId = this.safeString (order, 'Exchange');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = this.parseSymbol (marketId);
- }
- }
+ parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
+ if (this.options['fetchClosedOrdersFilterBySince']) {
+ return super.parseOrders (orders, market, since, limit, params);
} else {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ return super.parseOrders (orders, market, undefined, limit, params);
}
- let timestamp = undefined;
- const opened = this.safeString (order, 'Opened');
- if (opened !== undefined) {
- timestamp = this.parse8601 (opened + '+00:00');
- }
- const created = this.safeString (order, 'Created');
- if (created !== undefined) {
- timestamp = this.parse8601 (created + '+00:00');
- }
- let lastTradeTimestamp = undefined;
- const lastTimestamp = this.safeString (order, 'TimeStamp');
- if (lastTimestamp !== undefined) {
- lastTradeTimestamp = this.parse8601 (lastTimestamp + '+00:00');
- }
- const closed = this.safeString (order, 'Closed');
- if (closed !== undefined) {
- lastTradeTimestamp = this.parse8601 (closed + '+00:00');
- }
- if (timestamp === undefined) {
- timestamp = lastTradeTimestamp;
- }
- let fee = undefined;
- const feeCost = this.safeFloat2 (order, 'Commission', 'CommissionPaid');
- if (feeCost !== undefined) {
- fee = {
- 'cost': feeCost,
- };
- if (market !== undefined) {
- fee['currency'] = market['quote'];
- } else if (symbol !== undefined) {
- const currencyIds = symbol.split ('/');
- const quoteCurrencyId = currencyIds[1];
- fee['currency'] = this.safeCurrencyCode (quoteCurrencyId);
- }
- }
- let price = this.safeFloat (order, 'Limit');
- let cost = this.safeFloat (order, 'Price');
- const amount = this.safeFloat (order, 'Quantity');
- const remaining = this.safeFloat (order, 'QuantityRemaining');
- let filled = undefined;
- if (amount !== undefined && remaining !== undefined) {
- filled = amount - remaining;
- if ((status === 'closed') && (remaining > 0)) {
- status = 'canceled';
- }
- }
- if (!cost) {
- if (price && filled) {
- cost = price * filled;
- }
- }
- if (!price) {
- if (cost && filled) {
- price = cost / filled;
- }
- }
- const average = this.safeFloat (order, 'PricePerUnit');
- const id = this.safeString2 (order, 'OrderUuid', 'OrderId');
- return {
- 'info': order,
- 'id': id,
- 'clientOrderId': undefined,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
- 'lastTradeTimestamp': lastTradeTimestamp,
- 'symbol': symbol,
- 'type': 'limit',
- 'side': side,
- 'price': price,
- 'cost': cost,
- 'average': average,
- 'amount': amount,
- 'filled': filled,
- 'remaining': remaining,
- 'status': status,
- 'fee': fee,
- 'trades': undefined,
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'CLOSED': 'closed',
+ 'OPEN': 'open',
+ 'CANCELLED': 'canceled',
+ 'CANCELED': 'canceled',
};
+ return this.safeString (statuses, status, status);
}
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
let response = undefined;
try {
- const orderIdField = this.getOrderIdField ();
- const request = {};
- request[orderIdField] = id;
- response = await this.accountGetOrder (this.extend (request, params));
+ const request = {
+ 'orderId': id,
+ };
+ response = await this.privateGetOrdersOrderId (this.extend (request, params));
} catch (e) {
if (this.last_json_response) {
const message = this.safeString (this.last_json_response, 'message');
@@ -1230,10 +1107,7 @@ module.exports = class bittrex extends Exchange {
}
throw e;
}
- if (!response['result']) {
- throw new OrderNotFound (this.id + ' order ' + id + ' not found');
- }
- return this.parseOrder (response['result']);
+ return this.parseOrder (response);
}
orderToTrade (order) {
@@ -1266,33 +1140,6 @@ module.exports = class bittrex extends Exchange {
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const orders = await this.fetchClosedOrders (symbol, since, limit, params);
- return this.ordersToTrades (orders);
- }
-
- async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- const method = this.safeString (this.options, 'fetchClosedOrdersMethod', 'fetch_closed_orders_v3');
- return await this[method] (symbol, since, limit, params);
- }
-
- async fetchClosedOrdersV2 (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
- const request = {};
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['market'] = market['id'];
- }
- const response = await this.accountGetOrderhistory (this.extend (request, params));
- const result = this.safeValue (response, 'result', []);
- const orders = this.parseOrders (result, market, since, limit);
- if (symbol !== undefined) {
- return this.filterBySymbol (orders, symbol);
- }
- return orders;
- }
-
- async fetchClosedOrdersV3 (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
if (limit !== undefined) {
@@ -1306,39 +1153,59 @@ module.exports = class bittrex extends Exchange {
market = this.market (symbol);
// because of this line we will have to rethink the entire v3
// in other words, markets define all the rest of the API
- // and v3 market ids are reversed in comparison to v2
+ // and v3 market ids are reversed in comparison to v1
// v3 has to be a completely separate implementation
// otherwise we will have to shuffle symbols and currencies everywhere
// which is prone to errors, as was shown here
// https://github.com/ccxt/ccxt/pull/5219#issuecomment-499646209
request['marketSymbol'] = market['base'] + '-' + market['quote'];
}
- const response = await this.v3GetOrdersClosed (this.extend (request, params));
- const orders = this.parseOrders (response, market, since, limit);
- if (symbol !== undefined) {
- return this.filterBySymbol (orders, symbol);
+ const response = await this.privateGetOrdersClosed (this.extend (request, params));
+ const orders = this.parseOrders (response, market);
+ const trades = this.ordersToTrades (orders);
+ return this.filterBySymbolSinceLimit (trades, symbol, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ if (limit !== undefined) {
+ request['pageSize'] = limit;
}
- return orders;
+ if (since !== undefined) {
+ request['startDate'] = this.ymdhms (since, 'T') + 'Z';
+ }
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ // because of this line we will have to rethink the entire v3
+ // in other words, markets define all the rest of the API
+ // and v3 market ids are reversed in comparison to v1
+ // v3 has to be a completely separate implementation
+ // otherwise we will have to shuffle symbols and currencies everywhere
+ // which is prone to errors, as was shown here
+ // https://github.com/ccxt/ccxt/pull/5219#issuecomment-499646209
+ request['marketSymbol'] = market['base'] + '-' + market['quote'];
+ }
+ const response = await this.privateGetOrdersClosed (this.extend (request, params));
+ return this.parseOrders (response, market, since, limit);
}
async fetchDepositAddress (code, params = {}) {
await this.loadMarkets ();
const currency = this.currency (code);
const request = {
- 'currency': currency['id'],
+ 'currencySymbol': currency['id'],
};
- const response = await this.accountGetDepositaddress (this.extend (request, params));
- //
- // { "success": false, "message": "ADDRESS_GENERATING", "result": null }
- //
- // { success: true,
- // message: "",
- // result: { Currency: "INCNT",
- // Address: "3PHvQt9bK21f7eVQVdJzrNPcsMzXabEA5Ha" } } }
- //
- let address = this.safeString (response['result'], 'Address');
- const message = this.safeString (response, 'message');
- if (!address || message === 'ADDRESS_GENERATING') {
+ const response = await this.privateGetAddressesCurrencySymbol (this.extend (request, params));
+ // {
+ // "status": "PROVISIONED",
+ // "currencySymbol": "BTC",
+ // "cryptoAddress": "1PhmYjnJPZH5NUwV8AUjqkeDkCBpbE2xqX"
+ // }
+ let address = this.safeString (response, 'cryptoAddress');
+ const message = this.safeString (response, 'status');
+ if (!address || message === 'REQUESTED') {
throw new AddressPending (this.id + ' the address for ' + code + ' is being generated (pending, not ready yet, retry again later)');
}
let tag = undefined;
@@ -1360,46 +1227,30 @@ module.exports = class bittrex extends Exchange {
await this.loadMarkets ();
const currency = this.currency (code);
const request = {
- 'currency': currency['id'],
+ 'currencySymbol': currency['id'],
'quantity': amount,
- 'address': address,
+ 'cryptoAddress': address,
};
if (tag !== undefined) {
- request['paymentid'] = tag;
+ request['cryptoAddressTag'] = tag;
}
- const response = await this.accountGetWithdraw (this.extend (request, params));
- const result = this.safeValue (response, 'result', {});
- const id = this.safeString (result, 'uuid');
+ const response = await this.privatePostWithdrawals (this.extend (request, params));
+ const id = this.safeString (response, 'id');
return {
'info': response,
'id': id,
};
}
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ sign (path, api = 'v3', method = 'GET', params = {}, headers = undefined, body = undefined) {
let url = this.implodeParams (this.urls['api'][api], {
'hostname': this.hostname,
}) + '/';
- if (api !== 'v2' && api !== 'v3' && api !== 'v3public') {
+ if (api === 'private') {
url += this.version + '/';
- }
- if (api === 'public') {
- url += api + '/' + method.toLowerCase () + path;
- if (Object.keys (params).length) {
- url += '?' + this.urlencode (params);
- }
- } else if (api === 'v3public') {
- url += path;
- if (Object.keys (params).length) {
- url += '?' + this.urlencode (params);
- }
- } else if (api === 'v2') {
- url += path;
- if (Object.keys (params).length) {
- url += '?' + this.urlencode (params);
- }
- } else if (api === 'v3') {
- url += path;
+ this.checkRequiredCredentials ();
+ url += this.implodeParams (path, params);
+ params = this.omit (params, this.extractParams (path));
let hashString = '';
if (method === 'POST') {
body = this.json (params);
@@ -1430,21 +1281,14 @@ module.exports = class bittrex extends Exchange {
headers['Content-Type'] = 'application/json';
}
} else {
- this.checkRequiredCredentials ();
- url += api + '/';
- if (((api === 'account') && (path !== 'withdraw')) || (path === 'openorders')) {
- url += method.toLowerCase ();
+ if (api === 'public') {
+ url += this.version + '/';
}
- const request = {
- 'apikey': this.apiKey,
- };
- const disableNonce = this.safeValue (this.options, 'disableNonce');
- if ((disableNonce === undefined) || !disableNonce) {
- request['nonce'] = this.nonce ();
+ url += this.implodeParams (path, params);
+ params = this.omit (params, this.extractParams (path));
+ if (Object.keys (params).length) {
+ url += '?' + this.urlencode (params);
}
- url += path + '?' + this.urlencode (this.extend (request, params));
- const signature = this.hmac (this.encode (url), this.encode (this.secret), 'sha512');
- headers = { 'apisign': signature };
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
@@ -1463,16 +1307,14 @@ module.exports = class bittrex extends Exchange {
const code = this.safeString (response, 'code');
if (code !== undefined) {
this.throwExactlyMatchedException (this.exceptions['exact'], code, feedback);
- if (code !== undefined) {
- this.throwBroadlyMatchedException (this.exceptions['broad'], code, feedback);
- }
+ this.throwBroadlyMatchedException (this.exceptions['broad'], code, feedback);
}
// throw new ExchangeError (this.id + ' malformed response ' + this.json (response));
return;
}
if (typeof success === 'string') {
// bleutrade uses string instead of boolean
- success = (success === 'true') ? true : false;
+ success = (success === 'true');
}
if (!success) {
const message = this.safeString (response, 'message');
@@ -1528,13 +1370,4 @@ module.exports = class bittrex extends Exchange {
}
}
}
-
- async request (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- const response = await this.fetch2 (path, api, method, params, headers, body);
- // a workaround for APIKEY_INVALID
- if ((api === 'account') || (api === 'market')) {
- this.options['hasAlreadyAuthenticatedSuccessfully'] = true;
- }
- return response;
- }
};
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitvavo.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitvavo.js
new file mode 100644
index 000000000..10d62cfeb
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitvavo.js
@@ -0,0 +1,1495 @@
+'use strict';
+
+// ----------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, BadSymbol, AuthenticationError, InsufficientFunds, InvalidOrder, ArgumentsRequired, OrderNotFound, InvalidAddress, BadRequest, RateLimitExceeded, PermissionDenied, ExchangeNotAvailable, AccountSuspended, OnMaintenance } = require ('./base/errors');
+const { TRUNCATE } = require ('./base/functions/number');
+
+// ----------------------------------------------------------------------------
+
+module.exports = class bitvavo extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'bitvavo',
+ 'name': 'Bitvavo',
+ 'countries': [ 'NL' ], // Netherlands
+ 'rateLimit': 500,
+ 'version': 'v2',
+ 'certified': true,
+ 'pro': true,
+ 'has': {
+ 'CORS': false,
+ 'publicAPI': true,
+ 'privateAPI': true,
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchMarkets': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '5m': '5m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '2h': '2h',
+ '4h': '4h',
+ '6h': '6h',
+ '8h': '8h',
+ '12h': '12h',
+ '1d': '1d',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/83165440-2f1cf200-a116-11ea-9046-a255d09fb2ed.jpg',
+ 'api': {
+ 'public': 'https://api.bitvavo.com',
+ 'private': 'https://api.bitvavo.com',
+ },
+ 'www': 'https://bitvavo.com/',
+ 'doc': 'https://docs.bitvavo.com/',
+ 'fees': 'https://bitvavo.com/en/fees',
+ 'referral': 'https://bitvavo.com/?a=24F34952F7',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'time',
+ 'markets',
+ 'assets',
+ '{market}/book',
+ '{market}/trades',
+ '{market}/candles',
+ 'ticker/price',
+ 'ticker/book',
+ 'ticker/24h',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'order',
+ 'orders',
+ 'ordersOpen',
+ 'trades',
+ 'balance',
+ 'deposit',
+ 'depositHistory',
+ 'withdrawalHistory',
+ ],
+ 'post': [
+ 'order',
+ 'withdrawal',
+ ],
+ 'put': [
+ 'order',
+ ],
+ 'delete': [
+ 'order',
+ 'orders',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.25 / 100,
+ 'maker': 0.20 / 100,
+ 'tiers': {
+ 'taker': [
+ [ 0, 0.0025 ],
+ [ 50000, 0.0024 ],
+ [ 100000, 0.0022 ],
+ [ 250000, 0.0020 ],
+ [ 500000, 0.0018 ],
+ [ 1000000, 0.0016 ],
+ [ 2500000, 0.0014 ],
+ [ 5000000, 0.0012 ],
+ [ 10000000, 0.0010 ],
+ ],
+ 'maker': [
+ [ 0, 0.0020 ],
+ [ 50000, 0.0015 ],
+ [ 100000, 0.0010 ],
+ [ 250000, 0.0006 ],
+ [ 500000, 0.0003 ],
+ [ 1000000, 0.0001 ],
+ [ 2500000, -0.0001 ],
+ [ 5000000, -0.0003 ],
+ [ 10000000, -0.0005 ],
+ ],
+ },
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ },
+ 'exceptions': {
+ 'exact': {
+ '101': ExchangeError, // Unknown error. Operation may or may not have succeeded.
+ '102': BadRequest, // Invalid JSON.
+ '103': RateLimitExceeded, // You have been rate limited. Please observe the Bitvavo-Ratelimit-AllowAt header to see when you can send requests again. Failure to respect this limit will result in an IP ban. The default value is 1000 weighted requests per minute. Please contact support if you wish to increase this limit.
+ '104': RateLimitExceeded, // You have been rate limited by the number of new orders. The default value is 100 new orders per second or 100.000 new orders per day. Please update existing orders instead of cancelling and creating orders. Please contact support if you wish to increase this limit.
+ '105': PermissionDenied, // Your IP or API key has been banned for not respecting the rate limit. The ban expires at ${expiryInMs}.
+ '107': ExchangeNotAvailable, // The matching engine is overloaded. Please wait 500ms and resubmit your order.
+ '108': ExchangeNotAvailable, // The matching engine could not process your order in time. Please consider increasing the access window or resubmit your order.
+ '109': ExchangeNotAvailable, // The matching engine did not respond in time. Operation may or may not have succeeded.
+ '110': BadRequest, // Invalid endpoint. Please check url and HTTP method.
+ '200': BadRequest, // ${param} url parameter is not supported. Please note that parameters are case-sensitive and use body parameters for PUT and POST requests.
+ '201': BadRequest, // ${param} body parameter is not supported. Please note that parameters are case-sensitive and use url parameters for GET and DELETE requests.
+ '202': BadRequest, // ${param} order parameter is not supported. Please note that certain parameters are only allowed for market or limit orders.
+ '203': BadSymbol, // {"errorCode":203,"error":"symbol parameter is required."}
+ '204': BadRequest, // ${param} parameter is not supported.
+ '205': BadRequest, // ${param} parameter is invalid.
+ '206': BadRequest, // Use either ${paramA} or ${paramB}. The usage of both parameters at the same time is not supported.
+ '210': InvalidOrder, // Amount exceeds the maximum allowed amount (1000000000).
+ '211': InvalidOrder, // Price exceeds the maximum allowed amount (100000000000).
+ '212': InvalidOrder, // Amount is below the minimum allowed amount for this asset.
+ '213': InvalidOrder, // Price is below the minimum allowed amount (0.000000000000001).
+ '214': InvalidOrder, // Price is too detailed
+ '215': InvalidOrder, // Price is too detailed. A maximum of 15 digits behind the decimal point are allowed.
+ '216': InsufficientFunds, // {"errorCode":216,"error":"You do not have sufficient balance to complete this operation."}
+ '217': InvalidOrder, // {"errorCode":217,"error":"Minimum order size in quote currency is 5 EUR or 0.001 BTC."}
+ '230': ExchangeError, // The order is rejected by the matching engine.
+ '231': ExchangeError, // The order is rejected by the matching engine. TimeInForce must be GTC when markets are paused.
+ '232': BadRequest, // You must change at least one of amount, amountRemaining, price, timeInForce, selfTradePrevention or postOnly.
+ '233': InvalidOrder, // {"errorCode":233,"error":"Order must be active (status new or partiallyFilled) to allow updating/cancelling."}
+ '234': InvalidOrder, // Market orders cannot be updated.
+ '235': ExchangeError, // You can only have 100 open orders on each book.
+ '236': BadRequest, // You can only update amount or amountRemaining, not both.
+ '240': OrderNotFound, // {"errorCode":240,"error":"No order found. Please be aware that simultaneously updating the same order may return this error."}
+ '300': AuthenticationError, // Authentication is required for this endpoint.
+ '301': AuthenticationError, // {"errorCode":301,"error":"API Key must be of length 64."}
+ '302': AuthenticationError, // Timestamp is invalid. This must be a timestamp in ms. See Bitvavo-Access-Timestamp header or timestamp parameter for websocket.
+ '303': AuthenticationError, // Window must be between 100 and 60000 ms.
+ '304': AuthenticationError, // Request was not received within acceptable window (default 30s, or custom with Bitvavo-Access-Window header) of Bitvavo-Access-Timestamp header (or timestamp parameter for websocket).
+ // '304': AuthenticationError, // Authentication is required for this endpoint.
+ '305': AuthenticationError, // {"errorCode":305,"error":"No active API key found."}
+ '306': AuthenticationError, // No active API key found. Please ensure that you have confirmed the API key by e-mail.
+ '307': PermissionDenied, // This key does not allow access from this IP.
+ '308': AuthenticationError, // {"errorCode":308,"error":"The signature length is invalid (HMAC-SHA256 should return a 64 length hexadecimal string)."}
+ '309': AuthenticationError, // {"errorCode":309,"error":"The signature is invalid."}
+ '310': PermissionDenied, // This key does not allow trading actions.
+ '311': PermissionDenied, // This key does not allow showing account information.
+ '312': PermissionDenied, // This key does not allow withdrawal of funds.
+ '315': BadRequest, // Websocket connections may not be used in a browser. Please use REST requests for this.
+ '317': AccountSuspended, // This account is locked. Please contact support.
+ '400': ExchangeError, // Unknown error. Please contact support with a copy of your request.
+ '401': ExchangeError, // Deposits for this asset are not available at this time.
+ '402': PermissionDenied, // You need to verify your identitiy before you can deposit and withdraw digital assets.
+ '403': PermissionDenied, // You need to verify your phone number before you can deposit and withdraw digital assets.
+ '404': OnMaintenance, // Could not complete this operation, because our node cannot be reached. Possibly under maintenance.
+ '405': ExchangeError, // You cannot withdraw digital assets during a cooldown period. This is the result of newly added bank accounts.
+ '406': BadRequest, // {"errorCode":406,"error":"Your withdrawal is too small."}
+ '407': ExchangeError, // Internal transfer is not possible.
+ '408': InsufficientFunds, // {"errorCode":408,"error":"You do not have sufficient balance to complete this operation."}
+ '409': InvalidAddress, // {"errorCode":409,"error":"This is not a verified bank account."}
+ '410': ExchangeError, // Withdrawals for this asset are not available at this time.
+ '411': BadRequest, // You can not transfer assets to yourself.
+ '412': InvalidAddress, // {"errorCode":412,"error":"eth_address_invalid."}
+ '413': InvalidAddress, // This address violates the whitelist.
+ '414': ExchangeError, // You cannot withdraw assets within 2 minutes of logging in.
+ },
+ 'broad': {
+ 'start parameter is invalid': BadRequest, // {"errorCode":205,"error":"start parameter is invalid."}
+ 'symbol parameter is invalid': BadSymbol, // {"errorCode":205,"error":"symbol parameter is invalid."}
+ 'amount parameter is invalid': InvalidOrder, // {"errorCode":205,"error":"amount parameter is invalid."}
+ 'orderId parameter is invalid': InvalidOrder, // {"errorCode":205,"error":"orderId parameter is invalid."}
+ },
+ },
+ 'options': {
+ 'BITVAVO-ACCESS-WINDOW': 10000, // default 10 sec
+ 'fetchCurrencies': {
+ 'expires': 1000, // 1 second
+ },
+ },
+ 'commonCurrencies': {
+ 'MIOTA': 'IOTA', // https://github.com/ccxt/ccxt/issues/7487
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // { "time": 1590379519148 }
+ //
+ return this.safeInteger (response, 'time');
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetMarkets (params);
+ const currencies = await this.fetchCurrenciesFromCache (params);
+ const currenciesById = this.indexBy (currencies, 'symbol');
+ //
+ // [
+ // {
+ // "market":"ADA-BTC",
+ // "status":"trading", // "trading" "halted" "auction"
+ // "base":"ADA",
+ // "quote":"BTC",
+ // "pricePrecision":5,
+ // "minOrderInBaseAsset":"100",
+ // "minOrderInQuoteAsset":"0.001",
+ // "orderTypes": [ "market", "limit" ]
+ // }
+ // ]
+ //
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ const id = this.safeString (market, 'market');
+ const baseId = this.safeString (market, 'base');
+ const quoteId = this.safeString (market, 'quote');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const status = this.safeString (market, 'status');
+ const active = (status === 'trading');
+ const baseCurrency = this.safeValue (currenciesById, baseId);
+ let amountPrecision = undefined;
+ if (baseCurrency !== undefined) {
+ amountPrecision = this.safeInteger (baseCurrency, 'decimals', 8);
+ }
+ const precision = {
+ 'price': this.safeInteger (market, 'pricePrecision'),
+ 'amount': amountPrecision,
+ };
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'info': market,
+ 'active': active,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': this.safeFloat (market, 'minOrderInBaseAsset'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': this.safeFloat (market, 'minOrderInQuoteAsset'),
+ 'max': undefined,
+ },
+ },
+ });
+ }
+ return result;
+ }
+
+ async fetchCurrenciesFromCache (params = {}) {
+ // this method is now redundant
+ // currencies are now fetched before markets
+ const options = this.safeValue (this.options, 'fetchCurrencies', {});
+ const timestamp = this.safeInteger (options, 'timestamp');
+ const expires = this.safeInteger (options, 'expires', 1000);
+ const now = this.milliseconds ();
+ if ((timestamp === undefined) || ((now - timestamp) > expires)) {
+ const response = await this.publicGetAssets (params);
+ this.options['fetchCurrencies'] = this.extend (options, {
+ 'response': response,
+ 'timestamp': now,
+ });
+ }
+ return this.safeValue (this.options['fetchCurrencies'], 'response');
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.fetchCurrenciesFromCache (params);
+ //
+ // [
+ // {
+ // "symbol":"ADA",
+ // "name":"Cardano",
+ // "decimals":6,
+ // "depositFee":"0",
+ // "depositConfirmations":15,
+ // "depositStatus":"OK", // "OK", "MAINTENANCE", "DELISTED"
+ // "withdrawalFee":"0.2",
+ // "withdrawalMinAmount":"0.2",
+ // "withdrawalStatus":"OK", // "OK", "MAINTENANCE", "DELISTED"
+ // "networks": [ "Mainnet" ], // "ETH", "NEO", "ONT", "SEPA", "VET"
+ // "message":"",
+ // },
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const currency = response[i];
+ const id = this.safeString (currency, 'symbol');
+ const code = this.safeCurrencyCode (id);
+ const depositStatus = this.safeValue (currency, 'depositStatus');
+ const deposit = (depositStatus === 'OK');
+ const withdrawalStatus = this.safeValue (currency, 'withdrawalStatus');
+ const withdrawal = (withdrawalStatus === 'OK');
+ const active = deposit && withdrawal;
+ const name = this.safeString (currency, 'name');
+ const precision = this.safeInteger (currency, 'decimals', 8);
+ result[code] = {
+ 'id': id,
+ 'info': currency,
+ 'code': code,
+ 'name': name,
+ 'active': active,
+ 'fee': this.safeFloat (currency, 'withdrawalFee'),
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (currency, 'withdrawalMinAmount'),
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ };
+ const response = await this.publicGetTicker24h (this.extend (request, params));
+ //
+ // {
+ // "market":"ETH-BTC",
+ // "open":"0.022578",
+ // "high":"0.023019",
+ // "low":"0.022573",
+ // "last":"0.023019",
+ // "volume":"25.16366324",
+ // "volumeQuote":"0.57333305",
+ // "bid":"0.023039",
+ // "bidSize":"0.53500578",
+ // "ask":"0.023041",
+ // "askSize":"0.47859202",
+ // "timestamp":1590381666900
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker
+ //
+ // {
+ // "market":"ETH-BTC",
+ // "open":"0.022578",
+ // "high":"0.023019",
+ // "low":"0.022573",
+ // "last":"0.023019",
+ // "volume":"25.16366324",
+ // "volumeQuote":"0.57333305",
+ // "bid":"0.023039",
+ // "bidSize":"0.53500578",
+ // "ask":"0.023041",
+ // "askSize":"0.47859202",
+ // "timestamp":1590381666900
+ // }
+ //
+ const marketId = this.safeString (ticker, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const timestamp = this.safeInteger (ticker, 'timestamp');
+ const last = this.safeFloat (ticker, 'last');
+ const baseVolume = this.safeFloat (ticker, 'volume');
+ const quoteVolume = this.safeFloat (ticker, 'volumeQuote');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ let change = undefined;
+ let percentage = undefined;
+ let average = undefined;
+ const open = this.safeFloat (ticker, 'open');
+ if ((open !== undefined) && (last !== undefined)) {
+ change = last - open;
+ if (open > 0) {
+ percentage = change / open * 100;
+ }
+ average = this.sum (open, last) / 2;
+ }
+ const result = {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': this.safeFloat (ticker, 'bid'),
+ 'bidVolume': this.safeFloat (ticker, 'bidSize'),
+ 'ask': this.safeFloat (ticker, 'ask'),
+ 'askVolume': this.safeFloat (ticker, 'askSize'),
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined, // previous day close
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ return result;
+ }
+
+ parseTickers (tickers, symbols = undefined) {
+ const result = [];
+ for (let i = 0; i < tickers.length; i++) {
+ result.push (this.parseTicker (tickers[i]));
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetTicker24h (params);
+ //
+ // [
+ // {
+ // "market":"ADA-BTC",
+ // "open":"0.0000059595",
+ // "high":"0.0000059765",
+ // "low":"0.0000059595",
+ // "last":"0.0000059765",
+ // "volume":"2923.172",
+ // "volumeQuote":"0.01743483",
+ // "bid":"0.0000059515",
+ // "bidSize":"1117.630919",
+ // "ask":"0.0000059585",
+ // "askSize":"809.999739",
+ // "timestamp":1590382266324
+ // }
+ // ]
+ //
+ return this.parseTickers (response, symbols);
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ // 'limit': 500, // default 500, max 1000
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ // 'tradeIdFrom': '57b1159b-6bf5-4cde-9e2c-6bd6a5678baf',
+ // 'tradeIdTo': '57b1159b-6bf5-4cde-9e2c-6bd6a5678baf',
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ const response = await this.publicGetMarketTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id":"94154c98-6e8b-4e33-92a8-74e33fc05650",
+ // "timestamp":1590382761859,
+ // "amount":"0.06026079",
+ // "price":"8095.3",
+ // "side":"buy"
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // {
+ // "id":"94154c98-6e8b-4e33-92a8-74e33fc05650",
+ // "timestamp":1590382761859,
+ // "amount":"0.06026079",
+ // "price":"8095.3",
+ // "side":"buy"
+ // }
+ //
+ // createOrder, fetchOpenOrders, fetchOrders, editOrder (private)
+ //
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ //
+ // fetchMyTrades (private)
+ //
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "timestamp":1590505649245,
+ // "market":"ETH-EUR",
+ // "side":"sell",
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ //
+ // watchMyTrades (private)
+ //
+ // {
+ // event: 'fill',
+ // timestamp: 1590964470132,
+ // market: 'ETH-EUR',
+ // orderId: '85d082e1-eda4-4209-9580-248281a29a9a',
+ // fillId: '861d2da5-aa93-475c-8d9a-dce431bd4211',
+ // side: 'sell',
+ // amount: '0.1',
+ // price: '211.46',
+ // taker: true,
+ // fee: '0.056',
+ // feeCurrency: 'EUR'
+ // }
+ //
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'amount');
+ let cost = undefined;
+ if ((price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ const timestamp = this.safeInteger (trade, 'timestamp');
+ const side = this.safeString (trade, 'side');
+ const id = this.safeString2 (trade, 'id', 'fillId');
+ const marketId = this.safeInteger (trade, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const taker = this.safeValue (trade, 'taker');
+ let takerOrMaker = undefined;
+ if (taker !== undefined) {
+ takerOrMaker = taker ? 'taker' : 'maker';
+ }
+ const feeCost = this.safeFloat (trade, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (trade, 'feeCurrency');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ const orderId = this.safeString (trade, 'orderId');
+ return {
+ 'info': trade,
+ 'id': id,
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'order': orderId,
+ 'type': undefined,
+ 'side': side,
+ 'takerOrMaker': takerOrMaker,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'market': this.marketId (symbol),
+ };
+ if (limit !== undefined) {
+ request['depth'] = limit;
+ }
+ const response = await this.publicGetMarketBook (this.extend (request, params));
+ //
+ // {
+ // "market":"BTC-EUR",
+ // "nonce":35883831,
+ // "bids":[
+ // ["8097.4","0.6229099"],
+ // ["8097.2","0.64151283"],
+ // ["8097.1","0.24966294"],
+ // ],
+ // "asks":[
+ // ["8097.5","1.36916911"],
+ // ["8098.8","0.33462248"],
+ // ["8099.3","1.12908646"],
+ // ]
+ // }
+ //
+ const orderbook = this.parseOrderBook (response);
+ orderbook['nonce'] = this.safeInteger (response, 'nonce');
+ return orderbook;
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1590383700000,
+ // "8088.5",
+ // "8088.5",
+ // "8088.5",
+ // "8088.5",
+ // "0.04788623"
+ // ]
+ //
+ return [
+ this.safeInteger (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ 'interval': this.timeframes[timeframe],
+ // 'limit': 1440, // default 1440, max 1440
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 1440, max 1440
+ }
+ const response = await this.publicGetMarketCandles (this.extend (request, params));
+ //
+ // [
+ // [1590383700000,"8088.5","8088.5","8088.5","8088.5","0.04788623"],
+ // [1590383580000,"8091.3","8091.5","8091.3","8091.5","0.04931221"],
+ // [1590383520000,"8090.3","8092.7","8090.3","8092.5","0.04001286"],
+ // ]
+ //
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetBalance (params);
+ //
+ // [
+ // {
+ // "symbol": "BTC",
+ // "available": "1.57593193",
+ // "inOrder": "0.74832374"
+ // }
+ // ]
+ //
+ const result = { 'info': response };
+ for (let i = 0; i < response.length; i++) {
+ const balance = response[i];
+ const currencyId = this.safeString (balance, 'symbol');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = {
+ 'free': this.safeFloat (balance, 'available'),
+ 'used': this.safeFloat (balance, 'inOrder'),
+ };
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'symbol': currency['id'],
+ };
+ const response = await this.privateGetDeposit (this.extend (request, params));
+ //
+ // {
+ // "address": "0x449889e3234514c45d57f7c5a571feba0c7ad567",
+ // "paymentId": "10002653"
+ // }
+ //
+ const address = this.safeString (response, 'address');
+ const tag = this.safeString (response, 'paymentId');
+ this.checkAddress (address);
+ return {
+ 'currency': code,
+ 'address': address,
+ 'tag': tag,
+ 'info': response,
+ };
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ 'side': side,
+ 'orderType': type,
+ // 'amount': this.amountToPrecision (symbol, amount),
+ // 'price': this.priceToPrecision (symbol, price),
+ // 'amountQuote': this.costToPrecision (symbol, cost),
+ // 'timeInForce': 'GTC', // "GTC" "IOC" "FOK"
+ // 'selfTradePrevention': "decrementAndCancel", // "decrementAndCancel" "cancelOldest" "cancelNewest" "cancelBoth"
+ // 'postOnly': false,
+ // 'disableMarketProtection': false, // don't cancel if the next fill price is 10% worse than the best fill price
+ // 'responseRequired': true, // false is faster
+ };
+ if (type === 'market') {
+ let cost = undefined;
+ if (price !== undefined) {
+ cost = amount * price;
+ } else {
+ cost = this.safeFloat2 (params, 'cost', 'amountQuote');
+ }
+ if (cost !== undefined) {
+ const precision = market['precision']['price'];
+ request['amountQuote'] = this.decimalToPrecision (cost, TRUNCATE, precision, this.precisionMode);
+ } else {
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ }
+ params = this.omit (params, [ 'cost', 'amountQuote' ]);
+ } else if (type === 'limit') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ }
+ const response = await this.privatePostOrder (this.extend (request, params));
+ //
+ // {
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "market":"ETH-EUR",
+ // "created":1590505649241,
+ // "updated":1590505649241,
+ // "status":"filled",
+ // "side":"sell",
+ // "orderType":"market",
+ // "amount":"0.249825",
+ // "amountRemaining":"0",
+ // "onHold":"0",
+ // "onHoldCurrency":"ETH",
+ // "filledAmount":"0.249825",
+ // "filledAmountQuote":"45.84038925",
+ // "feePaid":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "fills":[
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ],
+ // "selfTradePrevention":"decrementAndCancel",
+ // "visible":false,
+ // "disableMarketProtection":false
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ let request = {};
+ const amountRemaining = this.safeFloat (params, 'amountRemaining');
+ params = this.omit (params, 'amountRemaining');
+ if (price !== undefined) {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ if (amount !== undefined) {
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ }
+ if (amountRemaining !== undefined) {
+ request['amountRemaining'] = this.amountToPrecision (symbol, amountRemaining);
+ }
+ request = this.extend (request, params);
+ if (Object.keys (request).length) {
+ request['orderId'] = id;
+ request['market'] = market['id'];
+ const response = await this.privatePutOrder (this.extend (request, params));
+ return this.parseOrder (response, market);
+ } else {
+ throw new ArgumentsRequired (this.id + ' editOrder requires an amount argument, or a price argument, or non-empty params');
+ }
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'orderId': id,
+ 'market': market['id'],
+ };
+ const response = await this.privateDeleteOrder (this.extend (request, params));
+ //
+ // {
+ // "orderId": "2e7ce7fc-44e2-4d80-a4a7-d079c4750b61"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market'] = market['id'];
+ }
+ const response = await this.privateDeleteOrders (this.extend (request, params));
+ //
+ // [
+ // {
+ // "orderId": "1be6d0df-d5dc-4b53-a250-3376f3b393e6"
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'orderId': id,
+ 'market': market['id'],
+ };
+ const response = await this.privateGetOrder (this.extend (request, params));
+ //
+ // {
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "market":"ETH-EUR",
+ // "created":1590505649241,
+ // "updated":1590505649241,
+ // "status":"filled",
+ // "side":"sell",
+ // "orderType":"market",
+ // "amount":"0.249825",
+ // "amountRemaining":"0",
+ // "onHold":"0",
+ // "onHoldCurrency":"ETH",
+ // "filledAmount":"0.249825",
+ // "filledAmountQuote":"45.84038925",
+ // "feePaid":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "fills":[
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ],
+ // "selfTradePrevention":"decrementAndCancel",
+ // "visible":false,
+ // "disableMarketProtection":false
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrders requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ // 'limit': 500,
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ // 'orderIdFrom': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ // 'orderIdTo': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 500, max 1000
+ }
+ const response = await this.privateGetOrders (this.extend (request, params));
+ //
+ // [
+ // {
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "market":"ETH-EUR",
+ // "created":1590505649241,
+ // "updated":1590505649241,
+ // "status":"filled",
+ // "side":"sell",
+ // "orderType":"market",
+ // "amount":"0.249825",
+ // "amountRemaining":"0",
+ // "onHold":"0",
+ // "onHoldCurrency":"ETH",
+ // "filledAmount":"0.249825",
+ // "filledAmountQuote":"45.84038925",
+ // "feePaid":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "fills":[
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ],
+ // "selfTradePrevention":"decrementAndCancel",
+ // "visible":false,
+ // "disableMarketProtection":false
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'market': market['id'],
+ // 'limit': 500,
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ // 'orderIdFrom': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ // 'orderIdTo': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 500, max 1000
+ }
+ const response = await this.privateGetOrdersOpen (this.extend (request, params));
+ //
+ // [
+ // {
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "market":"ETH-EUR",
+ // "created":1590505649241,
+ // "updated":1590505649241,
+ // "status":"filled",
+ // "side":"sell",
+ // "orderType":"market",
+ // "amount":"0.249825",
+ // "amountRemaining":"0",
+ // "onHold":"0",
+ // "onHoldCurrency":"ETH",
+ // "filledAmount":"0.249825",
+ // "filledAmountQuote":"45.84038925",
+ // "feePaid":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "fills":[
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ],
+ // "selfTradePrevention":"decrementAndCancel",
+ // "visible":false,
+ // "disableMarketProtection":false
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'new': 'open',
+ 'canceled': 'canceled',
+ 'canceledAuction': 'canceled',
+ 'canceledSelfTradePrevention': 'canceled',
+ 'canceledIOC': 'canceled',
+ 'canceledFOK': 'canceled',
+ 'canceledMarketProtection': 'canceled',
+ 'canceledPostOnly': 'canceled',
+ 'filled': 'closed',
+ 'partiallyFilled': 'open',
+ 'expired': 'canceled',
+ 'rejected': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // cancelOrder, cancelAllOrders
+ //
+ // {
+ // "orderId": "2e7ce7fc-44e2-4d80-a4a7-d079c4750b61"
+ // }
+ //
+ // createOrder, fetchOrder, fetchOpenOrders, fetchOrders, editOrder
+ //
+ // {
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "market":"ETH-EUR",
+ // "created":1590505649241,
+ // "updated":1590505649241,
+ // "status":"filled",
+ // "side":"sell",
+ // "orderType":"market",
+ // "amount":"0.249825",
+ // "amountRemaining":"0",
+ // "price": "183.49", // limit orders only
+ // "onHold":"0",
+ // "onHoldCurrency":"ETH",
+ // "filledAmount":"0.249825",
+ // "filledAmountQuote":"45.84038925",
+ // "feePaid":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "fills":[
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "timestamp":1590505649245,
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ],
+ // "selfTradePrevention":"decrementAndCancel",
+ // "visible":false,
+ // "disableMarketProtection":false
+ // "timeInForce": "GTC",
+ // "postOnly": true,
+ // }
+ //
+ const id = this.safeString (order, 'orderId');
+ const timestamp = this.safeInteger (order, 'created');
+ const marketId = this.safeString (order, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const side = this.safeString (order, 'side');
+ const type = this.safeString (order, 'orderType');
+ const price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'amount');
+ let remaining = this.safeFloat (order, 'amountRemaining');
+ let filled = this.safeFloat (order, 'filledAmount');
+ const remainingCost = this.safeFloat (order, 'remainingCost');
+ if ((remainingCost !== undefined) && (remainingCost === 0.0)) {
+ remaining = 0;
+ }
+ if ((amount !== undefined) && (remaining !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ const cost = this.safeFloat (order, 'filledAmountQuote');
+ let average = undefined;
+ if (cost !== undefined) {
+ if (filled) {
+ average = cost / filled;
+ }
+ }
+ let fee = undefined;
+ const feeCost = this.safeFloat (order, 'feePaid');
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (order, 'feeCurrency');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ let lastTradeTimestamp = undefined;
+ const rawTrades = this.safeValue (order, 'fills');
+ let trades = undefined;
+ if (rawTrades !== undefined) {
+ trades = this.parseTrades (rawTrades, market, undefined, undefined, {
+ 'symbol': symbol,
+ 'order': id,
+ 'side': side,
+ });
+ const numTrades = trades.length;
+ if (numTrades > 0) {
+ const lastTrade = this.safeValue (trades, numTrades - 1);
+ lastTradeTimestamp = lastTrade['timestamp'];
+ }
+ }
+ const timeInForce = this.safeString (order, 'timeInForce');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': timeInForce,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': trades,
+ };
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ // 'limit': 500,
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ // 'tradeIdFrom': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ // 'tradeIdTo': 'af76d6ce-9f7c-4006-b715-bb5d430652d0',
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 500, max 1000
+ }
+ const response = await this.privateGetTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id":"b0c86aa5-6ed3-4a2d-ba3a-be9a964220f4",
+ // "orderId":"af76d6ce-9f7c-4006-b715-bb5d430652d0",
+ // "timestamp":1590505649245,
+ // "market":"ETH-EUR",
+ // "side":"sell",
+ // "amount":"0.249825",
+ // "price":"183.49",
+ // "taker":true,
+ // "fee":"0.12038925",
+ // "feeCurrency":"EUR",
+ // "settled":true
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'symbol': currency['id'],
+ 'amount': this.currencyToPrecision (code, amount),
+ 'address': address, // address or IBAN
+ // 'internal': false, // transfer to another Bitvavo user address, no fees
+ // 'addWithdrawalFee': false, // true = add the fee on top, otherwise the fee is subtracted from the amount
+ };
+ if (tag !== undefined) {
+ request['paymentId'] = tag;
+ }
+ const response = await this.privatePostWithdrawal (this.extend (request, params));
+ //
+ // {
+ // "success": true,
+ // "symbol": "BTC",
+ // "amount": "1.5"
+ // }
+ //
+ return this.parseTransaction (response, currency);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'symbol': currency['id'],
+ // 'limit': 500, // default 500, max 1000
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['symbol'] = currency['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 500, max 1000
+ }
+ const response = await this.privateGetWithdrawalHistory (this.extend (request, params));
+ //
+ // [
+ // {
+ // "timestamp":1590531212000,
+ // "symbol":"ETH",
+ // "amount":"0.091",
+ // "fee":"0.009",
+ // "status":"awaiting_bitvavo_inspection",
+ // "address":"0xe42b309f1eE9F0cbf7f54CcF3bc2159eBfA6735b",
+ // "paymentId": "10002653",
+ // "txId": "927b3ea50c5bb52c6854152d305dfa1e27fc01d10464cf10825d96d69d235eb3",
+ // }
+ // ]
+ //
+ return this.parseTransactions (response, currency, since, limit);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'symbol': currency['id'],
+ // 'limit': 500, // default 500, max 1000
+ // 'start': since,
+ // 'end': this.milliseconds (),
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['symbol'] = currency['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 500, max 1000
+ }
+ const response = await this.privateGetDepositHistory (this.extend (request, params));
+ //
+ // [
+ // {
+ // "timestamp":1590492401000,
+ // "symbol":"ETH",
+ // "amount":"0.249825",
+ // "fee":"0",
+ // "status":"completed",
+ // "txId":"0x5167b473fd37811f9ef22364c3d54726a859ef9d98934b3a1e11d7baa8d2c2e2"
+ // }
+ // ]
+ //
+ return this.parseTransactions (response, currency, since, limit);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'awaiting_processing': 'pending',
+ 'awaiting_email_confirmation': 'pending',
+ 'awaiting_bitvavo_inspection': 'pending',
+ 'approved': 'pending',
+ 'sending': 'pending',
+ 'in_mempool': 'pending',
+ 'processed': 'pending',
+ 'completed': 'ok',
+ 'canceled': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // withdraw
+ //
+ // {
+ // "success": true,
+ // "symbol": "BTC",
+ // "amount": "1.5"
+ // }
+ //
+ // fetchWithdrawals
+ //
+ // {
+ // "timestamp": 1542967486256,
+ // "symbol": "BTC",
+ // "amount": "0.99994",
+ // "address": "BitcoinAddress",
+ // "paymentId": "10002653",
+ // "txId": "927b3ea50c5bb52c6854152d305dfa1e27fc01d10464cf10825d96d69d235eb3",
+ // "fee": "0.00006",
+ // "status": "awaiting_processing"
+ // }
+ //
+ // fetchDeposits
+ //
+ // {
+ // "timestamp":1590492401000,
+ // "symbol":"ETH",
+ // "amount":"0.249825",
+ // "fee":"0",
+ // "status":"completed",
+ // "txId":"0x5167b473fd37811f9ef22364c3d54726a859ef9d98934b3a1e11d7baa8d2c2e2"
+ // }
+ //
+ const id = undefined;
+ const timestamp = this.safeInteger (transaction, 'timestamp');
+ const currencyId = this.safeString (transaction, 'symbol');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const amount = this.safeFloat (transaction, 'amount');
+ const address = this.safeString (transaction, 'address');
+ const txid = this.safeString (transaction, 'txId');
+ let fee = undefined;
+ const feeCost = this.safeFloat (transaction, 'fee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': code,
+ };
+ }
+ let type = undefined;
+ if ('success' in transaction) {
+ type = 'withdrawal';
+ } else {
+ type = (status === undefined) ? 'deposit' : 'withdrawal';
+ }
+ const tag = this.safeString (transaction, 'paymentId');
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'addressFrom': undefined,
+ 'address': address,
+ 'addressTo': address,
+ 'tagFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'type': type,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': undefined,
+ 'fee': fee,
+ };
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const query = this.omit (params, this.extractParams (path));
+ let url = '/' + this.version + '/' + this.implodeParams (path, params);
+ const getOrDelete = (method === 'GET') || (method === 'DELETE');
+ if (getOrDelete) {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ }
+ if (api === 'private') {
+ this.checkRequiredCredentials ();
+ let payload = '';
+ if (!getOrDelete) {
+ if (Object.keys (query).length) {
+ body = this.json (query);
+ payload = body;
+ }
+ }
+ const timestamp = this.milliseconds ().toString ();
+ const auth = timestamp + method + url + payload;
+ const signature = this.hmac (this.encode (auth), this.encode (this.secret));
+ const accessWindow = this.safeString (this.options, 'BITVAVO-ACCESS-WINDOW', '10000');
+ headers = {
+ 'BITVAVO-ACCESS-KEY': this.apiKey,
+ 'BITVAVO-ACCESS-SIGNATURE': signature,
+ 'BITVAVO-ACCESS-TIMESTAMP': timestamp,
+ 'BITVAVO-ACCESS-WINDOW': accessWindow,
+ };
+ if (!getOrDelete) {
+ headers['Content-Type'] = 'application/json';
+ }
+ }
+ url = this.urls['api'][api] + url;
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ //
+ // {"errorCode":308,"error":"The signature length is invalid (HMAC-SHA256 should return a 64 length hexadecimal string)."}
+ // {"errorCode":203,"error":"symbol parameter is required."}
+ // {"errorCode":205,"error":"symbol parameter is invalid."}
+ //
+ const errorCode = this.safeString (response, 'errorCode');
+ const error = this.safeString (response, 'error');
+ if (errorCode !== undefined) {
+ const feedback = this.id + ' ' + body;
+ this.throwBroadlyMatchedException (this.exceptions['broad'], error, feedback);
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/bitz.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitz.js
similarity index 91%
rename from TaskServer/node_modules/ccxt/js/bitz.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitz.js
index 50fa901e8..9b28cd463 100644
--- a/TaskServer/node_modules/ccxt/js/bitz.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bitz.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, PermissionDenied, InvalidOrder, AuthenticationError, InsufficientFunds, OrderNotFound, DDoSProtection } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, PermissionDenied, InvalidOrder, AuthenticationError, InsufficientFunds, OrderNotFound, DDoSProtection, OnMaintenance, RateLimitExceeded } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -17,16 +17,26 @@ module.exports = class bitz extends Exchange {
'version': 'v2',
'userAgent': this.userAgents['chrome'],
'has': {
- 'fetchTickers': true,
+ 'cancelOrder': true,
+ 'cancelOrders': true,
+ 'createOrder': true,
+ 'createMarketOrder': false,
+ 'fetchBalance': true,
+ 'fetchDeposits': true,
+ 'fetchClosedOrders': true,
+ 'fetchMarkets': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'fetchOrders': true,
'fetchOrder': true,
- 'createMarketOrder': false,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTransactions': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1min',
@@ -42,7 +52,7 @@ module.exports = class bitz extends Exchange {
},
'hostname': 'apiv2.bitz.com',
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/35862606-4f554f14-0b5d-11e8-957d-35058c504b6f.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87443304-fec5e000-c5fd-11ea-98f8-ba8e67f7eaff.jpg',
'api': {
'market': 'https://{hostname}',
'trade': 'https://{hostname}',
@@ -62,6 +72,7 @@ module.exports = class bitz extends Exchange {
'tickerall',
'kline',
'symbolList',
+ 'getServerTime',
'currencyRate',
'currencyCoinRate',
'coinRate',
@@ -72,6 +83,7 @@ module.exports = class bitz extends Exchange {
'addEntrustSheet',
'cancelEntrustSheet',
'cancelAllEntrustSheet',
+ 'coinOut', // withdraw
'getUserHistoryEntrustSheet', // closed orders
'getUserNowEntrustSheet', // open orders
'getEntrustSheetInfo', // order
@@ -176,7 +188,9 @@ module.exports = class bitz extends Exchange {
'-109': AuthenticationError, // Invalid scretKey
'-110': DDoSProtection, // The number of access requests exceeded
'-111': PermissionDenied, // Current IP is not in the range of trusted IP
- '-112': ExchangeNotAvailable, // Service is under maintenance
+ '-112': OnMaintenance, // Service is under maintenance
+ '-114': RateLimitExceeded, // The number of daily requests has reached the limit
+ '-117': AuthenticationError, // The apikey expires
'-100015': AuthenticationError, // Trade password error
'-100044': ExchangeError, // Fail to request data
'-100101': ExchangeError, // Invalid symbol
@@ -350,14 +364,8 @@ module.exports = class bitz extends Exchange {
// krw: "318655.82" }
//
const timestamp = undefined;
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (ticker, 'symbol');
- market = this.safeValue (this.markets_by_id, marketId);
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (ticker, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
const last = this.safeFloat (ticker, 'now');
const open = this.safeFloat (ticker, 'open');
let change = undefined;
@@ -510,7 +518,22 @@ module.exports = class bitz extends Exchange {
});
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.marketGetGetServerTime (params);
+ //
+ // {
+ // "status":200,
+ // "msg":"",
+ // "data":[],
+ // "time":1555490875,
+ // "microtime":"0.35994200 1555490875",
+ // "source":"api"
+ // }
+ //
+ return this.safeTimestamp (response, 'time');
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -615,15 +638,17 @@ module.exports = class bitz extends Exchange {
return this.parseTrades (response['data'], market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
- // { time: "1535973420000",
- // open: "0.03975084",
- // high: "0.03975084",
- // low: "0.03967700",
- // close: "0.03967700",
- // volume: "12.4733",
- // datetime: "2018-09-03 19:17:00" }
+ // {
+ // time: "1535973420000",
+ // open: "0.03975084",
+ // high: "0.03975084",
+ // low: "0.03967700",
+ // close: "0.03967700",
+ // volume: "12.4733",
+ // datetime: "2018-09-03 19:17:00"
+ // }
//
return [
this.safeInteger (ohlcv, 'time'),
@@ -655,35 +680,27 @@ module.exports = class bitz extends Exchange {
}
const response = await this.marketGetKline (this.extend (request, params));
//
- // { status: 200,
- // msg: "",
- // data: { bars: [ { time: "1535973420000",
- // open: "0.03975084",
- // high: "0.03975084",
- // low: "0.03967700",
- // close: "0.03967700",
- // volume: "12.4733",
- // datetime: "2018-09-03 19:17:00" },
- // { time: "1535955480000",
- // open: "0.04009900",
- // high: "0.04016745",
- // low: "0.04009900",
- // close: "0.04012074",
- // volume: "74.4803",
- // datetime: "2018-09-03 14:18:00" } ],
- // resolution: "1min",
- // symbol: "eth_btc",
- // from: "1535973420000",
- // to: "1535955480000",
- // size: 300 },
- // time: 1535973435,
- // microtime: "0.56462100 1535973435",
- // source: "api" }
+ // {
+ // status: 200,
+ // msg: "",
+ // data: {
+ // bars: [
+ // { time: "1535973420000", open: "0.03975084", high: "0.03975084", low: "0.03967700", close: "0.03967700", volume: "12.4733", datetime: "2018-09-03 19:17:00" },
+ // { time: "1535955480000", open: "0.04009900", high: "0.04016745", low: "0.04009900", close: "0.04012074", volume: "74.4803", datetime: "2018-09-03 14:18:00" },
+ // ],
+ // resolution: "1min",
+ // symbol: "eth_btc",
+ // from: "1535973420000",
+ // to: "1535955480000",
+ // size: 300
+ // },
+ // time: 1535973435,
+ // microtime: "0.56462100 1535973435",
+ // source: "api"
+ // }
//
- const bars = this.safeValue (response['data'], 'bars', undefined);
- if (bars === undefined) {
- return [];
- }
+ const data = this.safeValue (response, 'data', {});
+ const bars = this.safeValue (data, 'bars', []);
return this.parseOHLCVs (bars, market, timeframe, since, limit);
}
@@ -761,8 +778,10 @@ module.exports = class bitz extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -1079,6 +1098,16 @@ module.exports = class bitz extends Exchange {
// "memo":""
// }
//
+ // withdraw
+ //
+ // {
+ // "id":397574,
+ // "email":"***@email.com",
+ // "coin":"usdt",
+ // "network_fee":"",
+ // "eid":23112
+ // }
+ //
let timestamp = this.safeInteger (transaction, 'updated');
if (timestamp === 0) {
timestamp = undefined;
@@ -1087,6 +1116,14 @@ module.exports = class bitz extends Exchange {
const code = this.safeCurrencyCode (currencyId, currency);
const type = this.safeStringLower (transaction, 'type');
const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ let fee = undefined;
+ const feeCost = this.safeFloat (transaction, 'network_fee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'code': code,
+ };
+ }
return {
'id': this.safeString (transaction, 'id'),
'txid': this.safeString (transaction, 'txid'),
@@ -1099,7 +1136,7 @@ module.exports = class bitz extends Exchange {
'currency': code,
'status': status,
'updated': timestamp,
- 'fee': undefined,
+ 'fee': fee,
'info': transaction,
};
}
@@ -1153,6 +1190,40 @@ module.exports = class bitz extends Exchange {
return this.parseTransactionsByType (type, transactions, code, since, limit);
}
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'coin': currency['id'],
+ 'number': this.currencyToPrecision (code, amount),
+ 'address': address,
+ // 'type': 'erc20', // omni, trc20, optional
+ };
+ if (tag !== undefined) {
+ request['memo'] = tag;
+ }
+ const response = await this.tradePostCoinOut (this.extend (request, params));
+ //
+ // {
+ // "status":200,
+ // "msg":"",
+ // "data":{
+ // "id":397574,
+ // "email":"***@email.com",
+ // "coin":"usdt",
+ // "network_fee":"",
+ // "eid":23112
+ // },
+ // "time":1552641646,
+ // "microtime":"0.70304500 1552641646",
+ // "source":"api"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTransaction (data, currency);
+ }
+
nonce () {
const currentTimestamp = this.seconds ();
if (currentTimestamp > this.options['lastNonceTimestamp']) {
diff --git a/TaskServer/node_modules/ccxt/js/bl3p.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bl3p.js
similarity index 96%
rename from TaskServer/node_modules/ccxt/js/bl3p.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bl3p.js
index 2cc0fce07..bb84442ec 100644
--- a/TaskServer/node_modules/ccxt/js/bl3p.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bl3p.js
@@ -17,14 +17,17 @@ module.exports = class bl3p extends Exchange {
'comment': 'An exchange market by BitonicNL',
'has': {
'CORS': false,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/28501752-60c21b82-6feb-11e7-818b-055ee6d0e754.jpg',
'api': 'https://api.bl3p.eu',
- 'www': [
- 'https://bl3p.eu',
- 'https://bitonic.nl',
- ],
+ 'www': 'https://bl3p.eu', // 'https://bitonic.nl'
'doc': [
'https://github.com/BitonicNL/bl3p-api/tree/master/docs',
'https://bl3p.eu/api',
@@ -225,7 +228,7 @@ module.exports = class bl3p extends Exchange {
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Rest-Key': this.apiKey,
- 'Rest-Sign': this.decode (signature),
+ 'Rest-Sign': signature,
};
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
diff --git a/TaskServer/node_modules/ccxt/js/bleutrade.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bleutrade.js
similarity index 91%
rename from TaskServer/node_modules/ccxt/js/bleutrade.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bleutrade.js
index 9bbd8a207..385e7e455 100644
--- a/TaskServer/node_modules/ccxt/js/bleutrade.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bleutrade.js
@@ -15,36 +15,36 @@ module.exports = class bleutrade extends Exchange {
'rateLimit': 1000,
'certified': false,
'has': {
+ 'cancelOrder': true,
'CORS': true,
- 'cancelOrder': false, // todo
- 'createLimitOrder': false, // todo
- 'createMarketOrder': false, // todo
- 'createOrder': false, // todo
- 'editOrder': false, // todo
- 'withdraw': false, // todo
- 'fetchTrades': false,
- 'fetchTickers': true,
- 'fetchTicker': true,
- 'fetchOrders': false,
+ 'createLimitOrder': false,
+ 'createMarketOrder': false,
+ 'createOrder': true,
+ 'editOrder': false,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchOpenOrders': true,
- 'fetchWithdrawals': true,
- 'fetchOrderTrades': false,
- 'fetchLedger': true,
+ 'fetchCurrencies': true,
'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchOrderTrades': false,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': false,
},
'timeframes': {
- '15m': '15m',
- '20m': '20m',
- '30m': '30m',
'1h': '1h',
- '2h': '2h',
- '3h': '3h',
'4h': '4h',
- '6h': '6h',
'8h': '8h',
- '12h': '12h',
'1d': '1d',
+ '1w': '1w',
},
'hostname': 'bleutrade.com',
'urls': {
@@ -53,7 +53,7 @@ module.exports = class bleutrade extends Exchange {
'v3Private': 'https://{hostname}/api/v3/private',
'v3Public': 'https://{hostname}/api/v3/public',
},
- 'www': ['https://bleutrade.com'],
+ 'www': 'https://bleutrade.com',
'doc': [
'https://app.swaggerhub.com/apis-docs/bleu/white-label/3.0.0',
],
@@ -105,6 +105,7 @@ module.exports = class bleutrade extends Exchange {
'exact': {
'ERR_INSUFICIENT_BALANCE': InsufficientFunds,
'ERR_LOW_VOLUME': BadRequest,
+ 'Invalid form': BadRequest,
},
'broad': {
'Order is not open': InvalidOrder,
@@ -121,7 +122,6 @@ module.exports = class bleutrade extends Exchange {
},
'options': {
'parseOrderStatus': true,
- 'symbolSeparator': '_',
},
});
// undocumented api calls
@@ -253,7 +253,7 @@ module.exports = class bleutrade extends Exchange {
'market': market['id'],
};
const response = await this.v3PublicGetGetmarketsummary (this.extend (request, params));
- const ticker = response['result'][0];
+ const ticker = this.safeValue (response, 'result', {});
return this.parseTicker (ticker, market);
}
@@ -290,18 +290,8 @@ module.exports = class bleutrade extends Exchange {
// MarketCurrency: 'Litecoin',
// BaseCurrency: 'Tether' }
const timestamp = this.parse8601 (this.safeString (ticker, 'TimeStamp'));
- let symbol = undefined;
const marketId = this.safeString (ticker, 'MarketName');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- symbol = this.parseSymbol (marketId);
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const previous = this.safeFloat (ticker, 'PrevDay');
const last = this.safeFloat (ticker, 'Last');
let change = undefined;
@@ -338,10 +328,9 @@ module.exports = class bleutrade extends Exchange {
};
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
- const timestamp = this.parse8601 (ohlcv['TimeStamp'] + '+00:00');
+ parseOHLCV (ohlcv, market = undefined) {
return [
- timestamp,
+ this.parse8601 (ohlcv['TimeStamp'] + '+00:00'),
this.safeFloat (ohlcv, 'Open'),
this.safeFloat (ohlcv, 'High'),
this.safeFloat (ohlcv, 'Low'),
@@ -359,7 +348,8 @@ module.exports = class bleutrade extends Exchange {
'count': limit,
};
const response = await this.v3PublicGetGetcandles (this.extend (request, params));
- return this.parseOHLCVs (response['result'], market, timeframe, since, limit);
+ const result = this.safeValue (response, 'result', []);
+ return this.parseOHLCVs (result, market, timeframe, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
@@ -411,13 +401,6 @@ module.exports = class bleutrade extends Exchange {
return this.parseOrders (items, market, since, limit);
}
- parseSymbol (id) {
- let [ base, quote ] = id.split (this.options['symbolSeparator']);
- base = this.safeCurrencyCode (base);
- quote = this.safeCurrencyCode (quote);
- return base + '/' + quote;
- }
-
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.v3PrivatePostGetbalances (params);
@@ -643,20 +626,8 @@ module.exports = class bleutrade extends Exchange {
// Comments: { String: '', Valid: true }
const side = this.safeString (order, 'Type').toLowerCase ();
const status = this.parseOrderStatus (this.safeString (order, 'Status'));
- let symbol = undefined;
const marketId = this.safeString (order, 'Exchange');
- if (marketId === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- } else {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = this.parseSymbol (marketId);
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
let timestamp = undefined;
if ('Created' in order) {
timestamp = this.parse8601 (order['Created'] + '+00:00');
@@ -690,8 +661,10 @@ module.exports = class bleutrade extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -818,22 +791,23 @@ module.exports = class bleutrade extends Exchange {
// {"success":false,"message":"Erro: Order is not open.","result":""} <-- 'error' is spelt wrong
// {"success":false,"message":"Error: Very low volume.","result":"ERR_LOW_VOLUME"}
// {"success":false,"message":"Error: Insuficient Balance","result":"ERR_INSUFICIENT_BALANCE"}
+ // {"success":false,"message":"Invalid form","result":null}
//
- if (body[0] === '{') {
- const success = this.safeValue (response, 'success');
- if (success === undefined) {
- throw new ExchangeError (this.id + ': malformed response: ' + this.json (response));
- }
- if (!success) {
- const feedback = this.id + ' ' + body;
- const errorCode = this.safeString (response, 'result');
+ const success = this.safeValue (response, 'success');
+ if (success === undefined) {
+ throw new ExchangeError (this.id + ': malformed response: ' + this.json (response));
+ }
+ if (!success) {
+ const feedback = this.id + ' ' + body;
+ const errorCode = this.safeString (response, 'result');
+ if (errorCode !== undefined) {
this.throwBroadlyMatchedException (this.exceptions['broad'], errorCode, feedback);
this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
- const errorMessage = this.safeString (response, 'message');
- this.throwBroadlyMatchedException (this.exceptions['broad'], errorMessage, feedback);
- this.throwExactlyMatchedException (this.exceptions['exact'], errorMessage, feedback);
- throw new ExchangeError (feedback);
}
+ const errorMessage = this.safeString (response, 'message');
+ this.throwBroadlyMatchedException (this.exceptions['broad'], errorMessage, feedback);
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorMessage, feedback);
+ throw new ExchangeError (feedback);
}
}
};
diff --git a/TaskServer/node_modules/ccxt/js/braziliex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/braziliex.js
similarity index 91%
rename from TaskServer/node_modules/ccxt/js/braziliex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/braziliex.js
index b082d1534..ac9d460c0 100644
--- a/TaskServer/node_modules/ccxt/js/braziliex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/braziliex.js
@@ -15,12 +15,19 @@ module.exports = class braziliex extends Exchange {
'countries': [ 'BR' ],
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchCurrencies': true,
- 'fetchTickers': true,
- 'fetchOpenOrders': true,
- 'fetchMyTrades': true,
'fetchDepositAddress': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/34703593-c4498674-f504-11e7-8d14-ff8e44fb78c1.jpg',
@@ -337,11 +344,11 @@ module.exports = class braziliex extends Exchange {
const ids = Object.keys (response);
for (let i = 0; i < ids.length; i++) {
const marketId = ids[i];
- const market = this.markets_by_id[marketId];
+ const market = this.safeMarket (marketId);
const symbol = market['symbol'];
result[symbol] = this.parseTicker (response[marketId], market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -423,16 +430,8 @@ module.exports = class braziliex extends Exchange {
// "date":"2017-03-12 15:13:33"
// }
//
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'market');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'market');
+ const symbol = this.safeSymbol (marketId, market, '_');
let timestamp = this.safeInteger (order, 'timestamp');
if (timestamp === undefined) {
timestamp = this.parse8601 (this.safeString (order, 'date'));
@@ -450,6 +449,7 @@ module.exports = class braziliex extends Exchange {
const id = this.safeString (order, 'order_number');
const fee = this.safeValue (order, 'fee'); // propagated from createOrder
const status = (filledPercentage === 1.0) ? 'closed' : 'open';
+ const side = this.safeString (order, 'type');
return {
'id': id,
'clientOrderId': undefined,
@@ -459,8 +459,10 @@ module.exports = class braziliex extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
- 'side': order['type'],
+ 'timeInForce': undefined,
+ 'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -484,30 +486,49 @@ module.exports = class braziliex extends Exchange {
'amount': amount,
};
const response = await this[method] (this.extend (request, params));
+ //
+ // sell
+ //
+ // {
+ // "success":1,
+ // "message":" ##RESERVED FOR ORDER / SELL / XMR_BTC / AMOUNT: 0.01 XMR / PRICE: 0.017 BTC / TOTAL: 0.00017000 BTC / FEE: 0.00002500 XMR ",
+ // "order_number":"590b962ba5b98335965fa0a8"
+ // }
+ //
+ // buy
+ //
+ // {
+ // "success":1,
+ // "message":" ##RESERVED FOR ORDER / BUY / XMR_BTC / AMOUNT: 0.005 XMR / PRICE: 0.017 BTC / TOTAL: 0.00008500 BTC / FEE: 0.00000021 BTC ",
+ // "order_number":"590b962ba5b98335965fa0c0"
+ // }
+ //
const success = this.safeInteger (response, 'success');
if (success !== 1) {
throw new InvalidOrder (this.id + ' ' + this.json (response));
}
- let parts = response['message'].split (' / ');
+ const message = this.safeString (response, 'message');
+ let parts = message.split (' / ');
parts = parts.slice (1);
const feeParts = parts[5].split (' ');
+ const amountParts = parts[2].split (' ');
+ const priceParts = parts[3].split (' ');
+ const totalParts = parts[4].split (' ');
const order = this.parseOrder ({
'timestamp': this.milliseconds (),
'order_number': response['order_number'],
- 'type': parts[0].toLowerCase (),
+ 'type': this.safeStringLower (parts, 0),
'market': parts[0].toLowerCase (),
- 'amount': parts[2].split (' ')[1],
- 'price': parts[3].split (' ')[1],
- 'total': parts[4].split (' ')[1],
+ 'amount': this.safeString (amountParts, 1),
+ 'price': this.safeString (priceParts, 1),
+ 'total': this.safeString (totalParts, 1),
'fee': {
- 'cost': parseFloat (feeParts[1]),
- 'currency': feeParts[2],
+ 'cost': this.safeFloat (feeParts, 1),
+ 'currency': this.safeString (feeParts, 2),
},
'progress': '0.0',
'info': response,
}, market);
- const id = order['id'];
- this.orders[id] = order;
return order;
}
@@ -542,7 +563,8 @@ module.exports = class braziliex extends Exchange {
'market': market['id'],
};
const response = await this.privatePostOpenOrders (this.extend (request, params));
- return this.parseOrders (response['order_open'], market, since, limit);
+ const orders = this.safeValue (response, 'order_open', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -552,7 +574,8 @@ module.exports = class braziliex extends Exchange {
'market': market['id'],
};
const response = await this.privatePostTradeHistory (this.extend (request, params));
- return this.parseTrades (response['trade_history'], market, since, limit);
+ const trades = this.safeValue (response, 'trade_history', []);
+ return this.parseTrades (trades, market, since, limit);
}
async fetchDepositAddress (code, params = {}) {
diff --git a/TaskServer/node_modules/ccxt/js/btcalpha.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcalpha.js
similarity index 94%
rename from TaskServer/node_modules/ccxt/js/btcalpha.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcalpha.js
index 4cdc5da22..441947aa1 100644
--- a/TaskServer/node_modules/ccxt/js/btcalpha.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcalpha.js
@@ -15,12 +15,19 @@ module.exports = class btcalpha extends Exchange {
'countries': [ 'US' ],
'version': 'v1',
'has': {
- 'fetchTicker': false,
- 'fetchOHLCV': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': false,
+ 'fetchTrades': true,
},
'timeframes': {
'1m': '1',
@@ -234,7 +241,17 @@ module.exports = class btcalpha extends Exchange {
return this.parseTrades (trades, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "time":1591296000,
+ // "open":0.024746,
+ // "close":0.024728,
+ // "low":0.024728,
+ // "high":0.024753,
+ // "volume":16.624
+ // }
+ //
return [
this.safeTimestamp (ohlcv, 'time'),
this.safeFloat (ohlcv, 'open'),
@@ -259,6 +276,13 @@ module.exports = class btcalpha extends Exchange {
request['since'] = parseInt (since / 1000);
}
const response = await this.publicGetChartsPairTypeChart (this.extend (request, params));
+ //
+ // [
+ // {"time":1591296000,"open":0.024746,"close":0.024728,"low":0.024728,"high":0.024753,"volume":16.624},
+ // {"time":1591295700,"open":0.024718,"close":0.02475,"low":0.024711,"high":0.02475,"volume":31.645},
+ // {"time":1591295400,"open":0.024721,"close":0.024717,"low":0.024711,"high":0.02473,"volume":65.071}
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -323,8 +347,10 @@ module.exports = class btcalpha extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': undefined,
'amount': amount,
'filled': filled,
diff --git a/TaskServer/node_modules/ccxt/js/btcbox.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcbox.js
similarity index 97%
rename from TaskServer/node_modules/ccxt/js/btcbox.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcbox.js
index 87d6af7fa..af988de09 100644
--- a/TaskServer/node_modules/ccxt/js/btcbox.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcbox.js
@@ -16,17 +16,23 @@ module.exports = class btcbox extends Exchange {
'rateLimit': 1000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchOrder': true,
- 'fetchOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
'fetchTickers': false,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/31275803-4df755a8-aaa1-11e7-9abb-11ec2fad9f2d.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87327317-98c55400-c53c-11ea-9a11-81f7d951cc74.jpg',
'api': 'https://www.btcbox.co.jp/api',
'www': 'https://www.btcbox.co.jp/',
- 'doc': 'https://www.btcbox.co.jp/help/asm',
+ 'doc': 'https://blog.btcbox.jp/en/archives/8762',
'fees': 'https://support.btcbox.co.jp/hc/en-us/articles/360001235694-Fees-introduction',
},
'api': {
@@ -299,9 +305,11 @@ module.exports = class btcbox extends Exchange {
'filled': filled,
'side': side,
'type': undefined,
+ 'timeInForce': undefined,
'status': status,
'symbol': symbol,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'trades': trades,
'fee': undefined,
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcmarkets.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcmarkets.js
new file mode 100644
index 000000000..15bbd9610
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcmarkets.js
@@ -0,0 +1,1055 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ArgumentsRequired, ExchangeError, OrderNotFound, InvalidOrder, InsufficientFunds, DDoSProtection, BadRequest } = require ('./base/errors');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class btcmarkets extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'btcmarkets',
+ 'name': 'BTC Markets',
+ 'countries': [ 'AU' ], // Australia
+ 'rateLimit': 1000, // market data cached for 1 second (trades cached for 2 seconds)
+ 'version': 'v3',
+ 'has': {
+ 'cancelOrder': true,
+ 'cancelOrders': true,
+ 'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': 'emulated',
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
+ 'fetchWithdrawals': true,
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/51840849/89731817-b3fb8480-da52-11ea-817f-783b08aaf32b.jpg',
+ 'api': {
+ 'public': 'https://api.btcmarkets.net',
+ 'private': 'https://api.btcmarkets.net',
+ },
+ 'www': 'https://btcmarkets.net',
+ 'doc': [
+ 'https://api.btcmarkets.net/doc/v3',
+ 'https://github.com/BTCMarkets/API',
+ ],
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'markets',
+ 'markets/{marketId}/ticker',
+ 'markets/{marketId}/trades',
+ 'markets/{marketId}/orderbook',
+ 'markets/{marketId}/candles',
+ 'markets/tickers',
+ 'markets/orderbooks',
+ 'time',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'orders',
+ 'orders/{id}',
+ 'batchorders/{ids}',
+ 'trades',
+ 'trades/{id}',
+ 'withdrawals',
+ 'withdrawals/{id}',
+ 'deposits',
+ 'deposits/{id}',
+ 'transfers',
+ 'transfers/{id}',
+ 'addresses',
+ 'withdrawal-fees',
+ 'assets',
+ 'accounts/me/trading-fees',
+ 'accounts/me/withdrawal-limits',
+ 'accounts/me/balances',
+ 'accounts/me/transactions',
+ 'reports/{id}',
+ ],
+ 'post': [
+ 'orders',
+ 'batchorders',
+ 'withdrawals',
+ 'reports',
+ ],
+ 'delete': [
+ 'orders',
+ 'orders/{id}',
+ 'batchorders/{ids}',
+ ],
+ 'put': [
+ 'orders/{id}',
+ ],
+ },
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '1h': '1h',
+ '1d': '1d',
+ },
+ 'exceptions': {
+ '3': InvalidOrder,
+ '6': DDoSProtection,
+ 'InsufficientFund': InsufficientFunds,
+ 'InvalidPrice': InvalidOrder,
+ 'InvalidAmount': InvalidOrder,
+ 'MissingArgument': InvalidOrder,
+ 'OrderAlreadyCancelled': InvalidOrder,
+ 'OrderNotFound': OrderNotFound,
+ 'OrderStatusIsFinal': InvalidOrder,
+ 'InvalidPaginationParameter': BadRequest,
+ },
+ 'fees': {
+ 'percentage': true,
+ 'tierBased': true,
+ 'maker': -0.05 / 100,
+ 'taker': 0.20 / 100,
+ },
+ 'options': {
+ 'fees': {
+ 'AUD': {
+ 'maker': 0.85 / 100,
+ 'taker': 0.85 / 100,
+ },
+ },
+ },
+ });
+ }
+
+ async fetchTransactionsWithMethod (method, code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ if (since !== undefined) {
+ request['after'] = since;
+ }
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ const response = await this[method] (this.extend (request, params));
+ return this.parseTransactions (response, currency, since, limit);
+ }
+
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsWithMethod ('privateGetTransfers', code, since, limit, params);
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsWithMethod ('privateGetDeposits', code, since, limit, params);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsWithMethod ('privateGetWithdrawals', code, since, limit, params);
+ }
+
+ parseTransactionStatus (status) {
+ // todo: find more statuses
+ const statuses = {
+ 'Complete': 'ok',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransactionType (type) {
+ const statuses = {
+ 'Withdraw': 'withdrawal',
+ 'Deposit': 'deposit',
+ };
+ return this.safeString (statuses, type, type);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // {
+ // "id": "6500230339",
+ // "assetName": "XRP",
+ // "amount": "500",
+ // "type": "Deposit",
+ // "creationTime": "2020-07-27T07:52:08.640000Z",
+ // "status": "Complete",
+ // "description": "RIPPLE Deposit, XRP 500",
+ // "fee": "0",
+ // "lastUpdate": "2020-07-27T07:52:08.665000Z",
+ // "paymentDetail": {
+ // "txId": "lsjflsjdfljsd",
+ // "address": "kjasfkjsdf?dt=873874545"
+ // }
+ // }
+ //
+ // {
+ // "id": "500985282",
+ // "assetName": "BTC",
+ // "amount": "0.42570126",
+ // "type": "Withdraw",
+ // "creationTime": "2017-07-29T12:49:03.931000Z",
+ // "status": "Complete",
+ // "description": "BTC withdraw from [nick-btcmarkets@snowmonkey.co.uk] to Address: 1B9DsnSYQ54VMqFHVJYdGoLMCYzFwrQzsj amount: 0.42570126 fee: 0.00000000",
+ // "fee": "0.0005",
+ // "lastUpdate": "2017-07-29T12:52:20.676000Z",
+ // "paymentDetail": {
+ // "txId": "fkjdsfjsfljsdfl",
+ // "address": "a;daddjas;djas"
+ // }
+ // }
+ //
+ // {
+ // "id": "505102262",
+ // "assetName": "XRP",
+ // "amount": "979.836",
+ // "type": "Deposit",
+ // "creationTime": "2017-07-31T08:50:01.053000Z",
+ // "status": "Complete",
+ // "description": "Ripple Deposit, X 979.8360",
+ // "fee": "0",
+ // "lastUpdate": "2017-07-31T08:50:01.290000Z"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (transaction, 'creationTime'));
+ const lastUpdate = this.parse8601 (this.safeString (transaction, 'lastUpdate'));
+ let type = this.parseTransactionType (this.safeStringLower (transaction, 'type'));
+ if (type === 'withdraw') {
+ type = 'withdrawal';
+ }
+ const cryptoPaymentDetail = this.safeValue (transaction, 'paymentDetail', {});
+ const txid = this.safeString (cryptoPaymentDetail, 'txId');
+ let address = this.safeString (cryptoPaymentDetail, 'address');
+ let tag = undefined;
+ if (address !== undefined) {
+ const addressParts = address.split ('?dt=');
+ const numParts = addressParts.length;
+ if (numParts > 1) {
+ address = addressParts[0];
+ tag = addressParts[1];
+ }
+ }
+ const addressTo = address;
+ const tagTo = tag;
+ const addressFrom = undefined;
+ const tagFrom = undefined;
+ const fee = this.safeFloat (transaction, 'fee');
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
+ const currencyId = this.safeString (transaction, 'assetName');
+ const code = this.safeCurrencyCode (currencyId);
+ let amount = this.safeFloat (transaction, 'amount');
+ if (fee) {
+ amount -= fee;
+ }
+ return {
+ 'id': this.safeString (transaction, 'id'),
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'address': address,
+ 'addressTo': addressTo,
+ 'addressFrom': addressFrom,
+ 'tag': tag,
+ 'tagTo': tagTo,
+ 'tagFrom': tagFrom,
+ 'type': type,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': lastUpdate,
+ 'fee': {
+ 'currency': code,
+ 'cost': fee,
+ },
+ 'info': transaction,
+ };
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetMarkets (params);
+ //
+ // [
+ // {
+ // "marketId":"COMP-AUD",
+ // "baseAssetName":"COMP",
+ // "quoteAssetName":"AUD",
+ // "minOrderAmount":"0.00007",
+ // "maxOrderAmount":"1000000",
+ // "amountDecimals":"8",
+ // "priceDecimals":"2"
+ // }
+ // ]
+ //
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ const baseId = this.safeString (market, 'baseAssetName');
+ const quoteId = this.safeString (market, 'quoteAssetName');
+ const id = this.safeString (market, 'marketId');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const fees = this.safeValue (this.safeValue (this.options, 'fees', {}), quote, this.fees);
+ const pricePrecision = this.safeFloat (market, 'priceDecimals');
+ const amountPrecision = this.safeFloat (market, 'amountDecimals');
+ const minAmount = this.safeFloat (market, 'minOrderAmount');
+ const maxAmount = this.safeFloat (market, 'maxOrderAmount');
+ let minPrice = undefined;
+ if (quote === 'AUD') {
+ minPrice = Math.pow (10, -pricePrecision);
+ }
+ const precision = {
+ 'amount': amountPrecision,
+ 'price': pricePrecision,
+ };
+ const limits = {
+ 'amount': {
+ 'min': minAmount,
+ 'max': maxAmount,
+ },
+ 'price': {
+ 'min': minPrice,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ };
+ result.push ({
+ 'info': market,
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'active': undefined,
+ 'maker': fees['maker'],
+ 'taker': fees['taker'],
+ 'limits': limits,
+ 'precision': precision,
+ });
+ }
+ return result;
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // {
+ // "timestamp": "2019-09-01T18:34:27.045000Z"
+ // }
+ //
+ return this.parse8601 (this.safeString (response, 'timestamp'));
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccountsMeBalances (params);
+ const result = { 'info': response };
+ for (let i = 0; i < response.length; i++) {
+ const balance = response[i];
+ const currencyId = this.safeString (balance, 'assetName');
+ const code = this.safeCurrencyCode (currencyId);
+ const total = this.safeFloat (balance, 'balance');
+ const used = this.safeFloat (balance, 'locked');
+ const account = this.account ();
+ account['used'] = used;
+ account['total'] = total;
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // "2020-09-12T18:30:00.000000Z",
+ // "14409.45", // open
+ // "14409.45", // high
+ // "14403.91", // low
+ // "14403.91", // close
+ // "0.01571701" // volume
+ // ]
+ //
+ return [
+ this.parse8601 (this.safeString (ohlcv, 0)),
+ this.safeFloat (ohlcv, 1), // open
+ this.safeFloat (ohlcv, 2), // high
+ this.safeFloat (ohlcv, 3), // low
+ this.safeFloat (ohlcv, 4), // close
+ this.safeFloat (ohlcv, 5), // volume
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'marketId': market['id'],
+ 'timeWindow': this.timeframes[timeframe],
+ // 'from': this.iso8601 (since),
+ // 'to': this.iso8601 (this.milliseconds ()),
+ // 'before': 1234567890123,
+ // 'after': 1234567890123,
+ // 'limit': limit, // default 10, max 200
+ };
+ if (since !== undefined) {
+ request['from'] = this.iso8601 (since);
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default is 10, max 200
+ }
+ const response = await this.publicGetMarketsMarketIdCandles (this.extend (request, params));
+ //
+ // [
+ // ["2020-09-12T18:30:00.000000Z","14409.45","14409.45","14403.91","14403.91","0.01571701"],
+ // ["2020-09-12T18:21:00.000000Z","14409.45","14409.45","14409.45","14409.45","0.0035"],
+ // ["2020-09-12T18:03:00.000000Z","14361.37","14361.37","14361.37","14361.37","0.00345221"],
+ // ]
+ //
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'marketId': market['id'],
+ };
+ const response = await this.publicGetMarketsMarketIdOrderbook (this.extend (request, params));
+ //
+ // {
+ // "marketId":"BTC-AUD",
+ // "snapshotId":1599936148941000,
+ // "asks":[
+ // ["14459.45","0.00456475"],
+ // ["14463.56","2"],
+ // ["14470.91","0.98"],
+ // ],
+ // "bids":[
+ // ["14421.01","0.52"],
+ // ["14421","0.75"],
+ // ["14418","0.3521"],
+ // ]
+ // }
+ //
+ const timestamp = this.safeIntegerProduct (response, 'snapshotId', 0.001);
+ const orderbook = this.parseOrderBook (response, timestamp);
+ orderbook['nonce'] = this.safeInteger (response, 'snapshotId');
+ return orderbook;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker
+ //
+ // {
+ // "marketId":"BAT-AUD",
+ // "bestBid":"0.3751",
+ // "bestAsk":"0.377",
+ // "lastPrice":"0.3769",
+ // "volume24h":"56192.97613335",
+ // "volumeQte24h":"21179.13270465",
+ // "price24h":"0.0119",
+ // "pricePct24h":"3.26",
+ // "low24h":"0.3611",
+ // "high24h":"0.3799",
+ // "timestamp":"2020-08-09T18:28:23.280000Z"
+ // }
+ //
+ let symbol = undefined;
+ const marketId = this.safeString (ticker, 'marketId');
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const [ baseId, quoteId ] = marketId.split ('-');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ const timestamp = this.parse8601 (this.safeString (ticker, 'timestamp'));
+ const last = this.safeFloat (ticker, 'lastPrice');
+ const baseVolume = this.safeFloat (ticker, 'volume24h');
+ const quoteVolume = this.safeFloat (ticker, 'volumeQte24h');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ const change = this.safeFloat (ticker, 'price24h');
+ const percentage = this.safeFloat (ticker, 'pricePct24h');
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high24h'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': this.safeFloat (ticker, 'bestBid'),
+ 'bidVolume': undefined,
+ 'ask': this.safeFloat (ticker, 'bestAsk'),
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': undefined,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': undefined,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'marketId': market['id'],
+ };
+ const response = await this.publicGetMarketsMarketIdTicker (this.extend (request, params));
+ //
+ // {
+ // "marketId":"BAT-AUD",
+ // "bestBid":"0.3751",
+ // "bestAsk":"0.377",
+ // "lastPrice":"0.3769",
+ // "volume24h":"56192.97613335",
+ // "volumeQte24h":"21179.13270465",
+ // "price24h":"0.0119",
+ // "pricePct24h":"3.26",
+ // "low24h":"0.3611",
+ // "high24h":"0.3799",
+ // "timestamp":"2020-08-09T18:28:23.280000Z"
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ async fetchTicker2 (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'id': market['id'],
+ };
+ const response = await this.publicGetMarketIdTick (this.extend (request, params));
+ return this.parseTicker (response, market);
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades
+ //
+ // {
+ // "id":"6191646611",
+ // "price":"539.98",
+ // "amount":"0.5",
+ // "timestamp":"2020-08-09T15:21:05.016000Z",
+ // "side":"Ask"
+ // }
+ //
+ // private fetchMyTrades
+ //
+ // {
+ // "id": "36014819",
+ // "marketId": "XRP-AUD",
+ // "timestamp": "2019-06-25T16:01:02.977000Z",
+ // "price": "0.67",
+ // "amount": "1.50533262",
+ // "side": "Ask",
+ // "fee": "0.00857285",
+ // "orderId": "3648306",
+ // "liquidityType": "Taker",
+ // "clientOrderId": "48"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (trade, 'timestamp'));
+ const marketId = this.safeString (trade, 'marketId');
+ let symbol = undefined;
+ let base = undefined;
+ let quote = undefined;
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const [ baseId, quoteId ] = marketId.split ('-');
+ base = this.safeCurrencyCode (baseId);
+ quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ base = market['base'];
+ quote = market['quote'];
+ }
+ let feeCurrencyCode = undefined;
+ if (quote === 'AUD') {
+ feeCurrencyCode = quote;
+ } else {
+ feeCurrencyCode = base;
+ }
+ let side = this.safeString (trade, 'side');
+ if (side === 'Bid') {
+ side = 'buy';
+ } else if (side === 'Ask') {
+ side = 'sell';
+ }
+ const id = this.safeString (trade, 'id');
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'amount');
+ let cost = undefined;
+ if (amount !== undefined) {
+ if (price !== undefined) {
+ cost = amount * price;
+ }
+ }
+ const orderId = this.safeString (trade, 'orderId');
+ let fee = undefined;
+ const feeCost = this.safeFloat (trade, 'fee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ const takerOrMaker = this.safeStringLower (trade, 'liquidityType');
+ return {
+ 'info': trade,
+ 'id': id,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'order': orderId,
+ 'symbol': symbol,
+ 'type': undefined,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'takerOrMaker': takerOrMaker,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ // 'since': 59868345231,
+ 'marketId': market['id'],
+ };
+ const response = await this.publicGetMarketsMarketIdTrades (this.extend (request, params));
+ //
+ // [
+ // {"id":"6191646611","price":"539.98","amount":"0.5","timestamp":"2020-08-09T15:21:05.016000Z","side":"Ask"},
+ // {"id":"6191646610","price":"539.99","amount":"0.5","timestamp":"2020-08-09T15:21:05.015000Z","side":"Ask"},
+ // {"id":"6191646590","price":"540","amount":"0.00233785","timestamp":"2020-08-09T15:21:04.171000Z","side":"Bid"},
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'marketId': market['id'],
+ // 'price': this.priceToPrecision (symbol, price),
+ 'amount': this.amountToPrecision (symbol, amount),
+ // 'type': 'Limit', // "Limit", "Market", "Stop Limit", "Stop", "Take Profit"
+ 'side': (side === 'buy') ? 'Bid' : 'Ask',
+ // 'triggerPrice': this.priceToPrecision (symbol, triggerPrice), // required for Stop, Stop Limit, Take Profit orders
+ // 'targetAmount': this.amountToPrecision (symbol, targetAmount), // target amount when a desired target outcome is required for order execution
+ // 'timeInForce': 'GTC', // GTC, FOK, IOC
+ // 'postOnly': false, // boolean if this is a post-only order
+ // 'selfTrade': 'A', // A = allow, P = prevent
+ // 'clientOrderId': this.uuid (),
+ };
+ const lowercaseType = type.toLowerCase ();
+ const orderTypes = this.safeValue (this.options, 'orderTypes', {
+ 'limit': 'Limit',
+ 'market': 'Market',
+ 'stop': 'Stop',
+ 'stop limit': 'Stop Limit',
+ 'take profit': 'Take Profit',
+ });
+ request['type'] = this.safeString (orderTypes, lowercaseType, type);
+ let priceIsRequired = false;
+ let triggerPriceIsRequired = false;
+ if (lowercaseType === 'limit') {
+ priceIsRequired = true;
+ // } else if (lowercaseType === 'market') {
+ // ...
+ // }
+ } else if (lowercaseType === 'stop limit') {
+ triggerPriceIsRequired = true;
+ priceIsRequired = true;
+ } else if (lowercaseType === 'take profit') {
+ triggerPriceIsRequired = true;
+ } else if (lowercaseType === 'stop') {
+ triggerPriceIsRequired = true;
+ }
+ if (priceIsRequired) {
+ if (price === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder() requires a price argument for a ' + type + 'order');
+ } else {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ }
+ if (triggerPriceIsRequired) {
+ const triggerPrice = this.safeFloat (params, 'triggerPrice');
+ params = this.omit (params, 'triggerPrice');
+ if (triggerPrice === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder() requires a triggerPrice parameter for a ' + type + 'order');
+ } else {
+ request['triggerPrice'] = this.priceToPrecision (symbol, triggerPrice);
+ }
+ }
+ const clientOrderId = this.safeString (params, 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['clientOrderId'] = clientOrderId;
+ }
+ params = this.omit (params, 'clientOrderId');
+ const response = await this.privatePostOrders (this.extend (request, params));
+ //
+ // {
+ // "orderId": "7524",
+ // "marketId": "BTC-AUD",
+ // "side": "Bid",
+ // "type": "Limit",
+ // "creationTime": "2019-08-30T11:08:21.956000Z",
+ // "price": "100.12",
+ // "amount": "1.034",
+ // "openAmount": "1.034",
+ // "status": "Accepted",
+ // "clientOrderId": "1234-5678",
+ // "timeInForce": "IOC",
+ // "postOnly": false,
+ // "selfTrade": "P",
+ // "triggerAmount": "105",
+ // "targetAmount": "1000"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrders (ids, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ for (let i = 0; i < ids.length; i++) {
+ ids[i] = parseInt (ids[i]);
+ }
+ const request = {
+ 'ids': ids,
+ };
+ return await this.privateDeleteBatchordersIds (this.extend (request, params));
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ return await this.privateDeleteOrdersId (this.extend (request, params));
+ }
+
+ calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) {
+ const market = this.markets[symbol];
+ const rate = market[takerOrMaker];
+ let currency = undefined;
+ let cost = undefined;
+ if (market['quote'] === 'AUD') {
+ currency = market['quote'];
+ cost = parseFloat (this.costToPrecision (symbol, amount * price));
+ } else {
+ currency = market['base'];
+ cost = parseFloat (this.amountToPrecision (symbol, amount));
+ }
+ return {
+ 'type': takerOrMaker,
+ 'currency': currency,
+ 'rate': rate,
+ 'cost': parseFloat (this.feeToPrecision (symbol, rate * cost)),
+ };
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'Accepted': 'open',
+ 'Placed': 'open',
+ 'Partially Matched': 'open',
+ 'Fully Matched': 'closed',
+ 'Cancelled': 'canceled',
+ 'Partially Cancelled': 'canceled',
+ 'Failed': 'rejected',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // "orderId": "7524",
+ // "marketId": "BTC-AUD",
+ // "side": "Bid",
+ // "type": "Limit",
+ // "creationTime": "2019-08-30T11:08:21.956000Z",
+ // "price": "100.12",
+ // "amount": "1.034",
+ // "openAmount": "1.034",
+ // "status": "Accepted",
+ // "clientOrderId": "1234-5678",
+ // "timeInForce": "IOC",
+ // "postOnly": false,
+ // "selfTrade": "P",
+ // "triggerAmount": "105",
+ // "targetAmount": "1000"
+ // }
+ //
+ const timestamp = this.parse8601 (this.safeString (order, 'creationTime'));
+ const marketId = this.safeString (order, 'marketId');
+ let symbol = undefined;
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const [ baseId, quoteId ] = marketId.split ('-');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ let side = this.safeString (order, 'side');
+ if (side === 'Bid') {
+ side = 'buy';
+ } else if (side === 'Ask') {
+ side = 'sell';
+ }
+ const type = this.safeStringLower (order, 'type');
+ const price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'amount');
+ const remaining = this.safeFloat (order, 'openAmount');
+ let filled = undefined;
+ if ((amount !== undefined) && (remaining !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ let cost = undefined;
+ if (price !== undefined) {
+ if (filled !== undefined) {
+ cost = price * filled;
+ }
+ }
+ const id = this.safeString (order, 'orderId');
+ const clientOrderId = this.safeString (order, 'clientOrderId');
+ const timeInForce = this.safeString (order, 'timeInForce');
+ const stopPrice = this.safeFloat (order, 'triggerPrice');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': timeInForce,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': stopPrice,
+ 'cost': cost,
+ 'amount': amount,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'average': undefined,
+ 'status': status,
+ 'trades': undefined,
+ 'fee': undefined,
+ };
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const response = await this.privateGetOrdersId (this.extend (request, params));
+ return this.parseOrder (response);
+ }
+
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'status': 'all',
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['marketId'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['after'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetOrders (this.extend (request, params));
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = { 'status': 'open' };
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const orders = await this.fetchOrders (symbol, since, limit, params);
+ return this.filterBy (orders, 'status', 'closed');
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['marketId'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['after'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id": "36014819",
+ // "marketId": "XRP-AUD",
+ // "timestamp": "2019-06-25T16:01:02.977000Z",
+ // "price": "0.67",
+ // "amount": "1.50533262",
+ // "side": "Ask",
+ // "fee": "0.00857285",
+ // "orderId": "3648306",
+ // "liquidityType": "Taker",
+ // "clientOrderId": "48"
+ // },
+ // {
+ // "id": "3568960",
+ // "marketId": "GNT-AUD",
+ // "timestamp": "2019-06-20T08:44:04.488000Z",
+ // "price": "0.1362",
+ // "amount": "0.85",
+ // "side": "Bid",
+ // "fee": "0.00098404",
+ // "orderId": "3543015",
+ // "liquidityType": "Maker"
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ lookupSymbolFromMarketId (marketId) {
+ let market = undefined;
+ let symbol = undefined;
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const [ baseId, quoteId ] = marketId.split ('-');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ }
+ return symbol;
+ }
+
+ nonce () {
+ return this.milliseconds ();
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let request = '/' + this.version + '/' + this.implodeParams (path, params);
+ const query = this.keysort (this.omit (params, this.extractParams (path)));
+ if (api === 'private') {
+ this.checkRequiredCredentials ();
+ const nonce = this.nonce ().toString ();
+ const secret = this.base64ToBinary (this.encode (this.secret));
+ let auth = method + request + nonce;
+ if ((method === 'GET') || (method === 'DELETE')) {
+ if (Object.keys (query).length) {
+ request += '?' + this.urlencode (query);
+ }
+ } else {
+ body = this.json (query);
+ auth += body;
+ }
+ const signature = this.hmac (this.encode (auth), secret, 'sha512', 'base64');
+ headers = {
+ 'Accept': 'application/json',
+ 'Accept-Charset': 'UTF-8',
+ 'Content-Type': 'application/json',
+ 'BM-AUTH-APIKEY': this.apiKey,
+ 'BM-AUTH-TIMESTAMP': nonce,
+ 'BM-AUTH-SIGNATURE': signature,
+ };
+ } else if (api === 'public') {
+ if (Object.keys (query).length) {
+ request += '?' + this.urlencode (query);
+ }
+ }
+ const url = this.urls['api'][api] + request;
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ if ('success' in response) {
+ if (!response['success']) {
+ const error = this.safeString (response, 'errorCode');
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions, error, feedback);
+ throw new ExchangeError (feedback);
+ }
+ }
+ // v3 api errors
+ if (code >= 400) {
+ const errorCode = this.safeString (response, 'code');
+ const message = this.safeString (response, 'message');
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions, errorCode, feedback);
+ this.throwExactlyMatchedException (this.exceptions, message, feedback);
+ throw new ExchangeError (feedback);
+ }
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/btctradeua.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btctradeua.js
similarity index 98%
rename from TaskServer/node_modules/ccxt/js/btctradeua.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btctradeua.js
index 553ec77f2..4d6743bf5 100644
--- a/TaskServer/node_modules/ccxt/js/btctradeua.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btctradeua.js
@@ -15,9 +15,15 @@ module.exports = class btctradeua extends Exchange {
'countries': [ 'UA' ], // Ukraine,
'rateLimit': 3000,
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
'signIn': true,
},
'urls': {
@@ -328,8 +334,10 @@ module.exports = class btctradeua extends Exchange {
'status': 'open',
'symbol': symbol,
'type': undefined,
+ 'timeInForce': undefined,
'side': this.safeString (order, 'type'),
'price': this.safeFloat (order, 'price'),
+ 'stopPrice': undefined,
'amount': this.safeFloat (order, 'amnt_trade'),
'filled': 0,
'remaining': this.safeFloat (order, 'amnt_trade'),
diff --git a/TaskServer/node_modules/ccxt/js/btcturk.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcturk.js
similarity index 95%
rename from TaskServer/node_modules/ccxt/js/btcturk.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcturk.js
index ecdf87034..24f79880b 100644
--- a/TaskServer/node_modules/ccxt/js/btcturk.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/btcturk.js
@@ -15,15 +15,22 @@ module.exports = class btcturk extends Exchange {
'countries': [ 'TR' ], // Turkey
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': true,
- 'fetchTickers': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchOHLCV': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'timeframes': {
'1d': '1d',
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27992709-18e15646-64a3-11e7-9fa2-b0950ec7712f.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87153926-efbef500-c2c0-11ea-9842-05b63612c4b9.jpg',
'api': 'https://www.btcturk.com/api',
'www': 'https://www.btcturk.com',
'doc': 'https://github.com/BTCTrader/broker-api-docs',
@@ -184,7 +191,7 @@ module.exports = class btcturk extends Exchange {
}
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -237,10 +244,9 @@ module.exports = class btcturk extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
- const timestamp = this.parse8601 (this.safeString (ohlcv, 'Time'));
+ parseOHLCV (ohlcv, market = undefined) {
return [
- timestamp,
+ this.parse8601 (this.safeString (ohlcv, 'Time')),
this.safeFloat (ohlcv, 'Open'),
this.safeFloat (ohlcv, 'High'),
this.safeFloat (ohlcv, 'Low'),
@@ -312,7 +318,7 @@ module.exports = class btcturk extends Exchange {
headers = {
'X-PCK': this.apiKey,
'X-Stamp': nonce,
- 'X-Signature': this.stringToBase64 (this.hmac (this.encode (auth), secret, 'sha256', 'binary')),
+ 'X-Signature': this.hmac (this.encode (auth), secret, 'sha256', 'base64'),
'Content-Type': 'application/x-www-form-urlencoded',
};
}
diff --git a/TaskServer/node_modules/ccxt/js/buda.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/buda.js
similarity index 98%
rename from TaskServer/node_modules/ccxt/js/buda.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/buda.js
index e92a1617a..96da5d093 100644
--- a/TaskServer/node_modules/ccxt/js/buda.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/buda.js
@@ -16,19 +16,25 @@ module.exports = class buda extends Exchange {
'rateLimit': 1000,
'version': 'v2',
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createDepositAddress': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
'fetchFundingFees': true,
+ 'fetchMarkets': true,
'fetchMyTrades': false,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
'fetchOrders': true,
'fetchTrades': true,
+ 'fetchTicker': true,
'fetchWithdrawals': true,
'withdraw': true,
},
@@ -533,16 +539,8 @@ module.exports = class buda extends Exchange {
parseOrder (order, market = undefined) {
const id = this.safeString (order, 'id');
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
- let symbol = undefined;
- if (market === undefined) {
- const marketId = order['market_id'];
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'market_id');
+ const symbol = this.safeSymbol (marketId, market);
const type = this.safeString (order, 'price_type');
const side = this.safeStringLower (order, 'type');
const status = this.parseOrderStatus (this.safeString (order, 'state'));
@@ -570,8 +568,10 @@ module.exports = class buda extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -755,7 +755,7 @@ module.exports = class buda extends Exchange {
const nonce = this.nonce ().toString ();
const components = [ method, '/api/' + this.version + '/' + request ];
if (body) {
- const base64Body = this.stringToBase64 (this.encode (body));
+ const base64Body = this.stringToBase64 (body);
components.push (this.decode (base64Body));
}
components.push (nonce);
diff --git a/TaskServer/node_modules/ccxt/js/bw.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bw.js
similarity index 97%
rename from TaskServer/node_modules/ccxt/js/bw.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bw.js
index dbd22c523..57a8a64c7 100644
--- a/TaskServer/node_modules/ccxt/js/bw.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bw.js
@@ -70,6 +70,7 @@ module.exports = class bw extends Exchange {
'www': 'https://www.bw.com',
'doc': 'https://github.com/bw-exchange/api_docs_en/wiki',
'fees': 'https://www.bw.com/feesRate',
+ 'referral': 'https://www.bw.com/regGetCommission/N3JuT1R3bWxKTE0',
},
'requiredCredentials': {
'apiKey': true,
@@ -332,16 +333,8 @@ module.exports = class bw extends Exchange {
// "469849357.2364" // quote volume
// ]
//
- let symbol = undefined;
const marketId = this.safeString (ticker, 0);
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.milliseconds ();
const close = parseFloat (this.safeValue (ticker, 1));
const bid = this.safeValue (ticker, 'bid', {});
@@ -429,7 +422,7 @@ module.exports = class bw extends Exchange {
result[symbol] = ticker;
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -557,7 +550,25 @@ module.exports = class bw extends Exchange {
return this.parseTrades (trades, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // "K",
+ // "305",
+ // "eth_btc",
+ // "1591511280",
+ // "0.02504",
+ // "0.02504",
+ // "0.02504",
+ // "0.02504",
+ // "0.0123",
+ // "0",
+ // "285740.17",
+ // "1M",
+ // "false",
+ // "0.000308"
+ // ]
+ //
return [
this.safeTimestamp (ohlcv, 3),
this.safeFloat (ohlcv, 4),
@@ -580,9 +591,18 @@ module.exports = class bw extends Exchange {
request['dataSize'] = limit;
}
const response = await this.publicGetApiDataV1Klines (this.extend (request, params));
+ //
+ // {
+ // "datas":[
+ // ["K","305","eth_btc","1591511280","0.02504","0.02504","0.02504","0.02504","0.0123","0","285740.17","1M","false","0.000308"],
+ // ["K","305","eth_btc","1591511220","0.02504","0.02504","0.02504","0.02504","0.0006","0","285740.17","1M","false","0.00001502"],
+ // ["K","305","eth_btc","1591511100","0.02505","0.02505","0.02504","0.02504","0.0012","-0.0399","285740.17","1M","false","0.00003005"],
+ // ],
+ // "resMsg":{"code":"1","method":null,"message":"success !"}
+ // }
+ //
const data = this.safeValue (response, 'datas', []);
- const ohlcvs = this.parseOHLCVs (data, market, timeframe, since, limit);
- return this.sortBy (ohlcvs, 0);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async fetchBalance (params = {}) {
@@ -705,9 +725,7 @@ module.exports = class bw extends Exchange {
// }
//
const marketId = this.safeString (order, 'marketId');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.safeInteger (order, 'createTime');
let side = this.safeString (order, 'type');
if (side === '0') {
@@ -740,10 +758,12 @@ module.exports = class bw extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
- 'symbol': this.safeString (market, 'symbol'),
+ 'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': undefined,
diff --git a/TaskServer/node_modules/ccxt/js/bybit.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bybit.js
similarity index 88%
rename from TaskServer/node_modules/ccxt/js/bybit.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bybit.js
index 5010ba98c..7a9159515 100644
--- a/TaskServer/node_modules/ccxt/js/bybit.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bybit.js
@@ -4,7 +4,7 @@
const Exchange = require ('./base/Exchange');
const { TICK_SIZE } = require ('./base/functions/number');
-const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce, NotSupported } = require ('./base/errors');
+const { AuthenticationError, ExchangeError, ArgumentsRequired, PermissionDenied, InvalidOrder, OrderNotFound, InsufficientFunds, BadRequest, RateLimitExceeded, InvalidNonce } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -18,27 +18,29 @@ module.exports = class bybit extends Exchange {
'userAgent': undefined,
'rateLimit': 100,
'has': {
+ 'cancelOrder': true,
'CORS': true,
- 'fetchMarkets': true,
- 'fetchBalance': true,
- 'fetchOHLCV': true,
+ 'cancelAllOrders': true,
+ 'createOrder': true,
'editOrder': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchOrderTrades': true,
'fetchTicker': true,
'fetchTickers': true,
- 'fetchOrderTrades': true,
- 'createOrder': true,
- 'cancelOrder': true,
- 'cancelAllOrders': true,
'fetchTime': true,
- 'fetchWithdrawals': true,
- 'fetchDeposits': false,
+ 'fetchTrades': true,
'fetchTransactions': false,
- 'fetchLedger': true,
+ 'fetchWithdrawals': true,
},
'timeframes': {
'1m': '1',
@@ -60,7 +62,7 @@ module.exports = class bybit extends Exchange {
'test': 'https://api-testnet.bybit.com',
'logo': 'https://user-images.githubusercontent.com/51840849/76547799-daff5b80-649e-11ea-87fb-3be9bac08954.jpg',
'api': 'https://api.bybit.com',
- 'www': 'https://www.bybit.com/',
+ 'www': 'https://www.bybit.com',
'doc': [
'https://bybit-exchange.github.io/docs/inverse/',
'https://bybit-exchange.github.io/docs/linear/',
@@ -77,31 +79,44 @@ module.exports = class bybit extends Exchange {
'tickers',
'trading-records',
'symbols',
+ 'liq-records',
+ 'mark-price-kline',
+ 'open-interest',
+ 'big-deal',
+ 'account-ratio',
'time',
'announcement',
],
},
'private': {
'get': [
+ 'order/list',
'order',
+ 'stop-order/list',
'stop-order',
'position/list',
'wallet/balance',
'execution/list',
+ 'trade/closed-pnl/list',
+ 'account/lcp',
+ 'exchange-order/list',
],
'post': [
'order/create',
'order/cancel',
'order/cancelAll',
+ 'order/replace',
+ 'stop-order/create',
+ 'stop-order/cancel',
'stop-order/cancelAll',
+ 'stop-order/replace',
],
},
'openapi': {
'get': [
- 'order/list',
- 'stop-order/list',
+ 'order/list', // deprecated
+ 'stop-order/list', // deprecated
'wallet/risk-limit/list',
- 'wallet/risk-limit',
'funding/prev-funding-rate',
'funding/prev-funding',
'funding/predicted-funding',
@@ -110,11 +125,12 @@ module.exports = class bybit extends Exchange {
'wallet/withdraw/list',
],
'post': [
- 'order/replace',
- 'stop-order/create',
- 'stop-order/cancel',
- 'stop-order/replace',
+ 'order/replace', // deprecated
+ 'stop-order/create', // deprecated
+ 'stop-order/cancel', // deprecated
+ 'stop-order/replace', // deprecated
'position/trading-stop',
+ 'wallet/risk-limit',
],
},
'publicLinear': {
@@ -123,6 +139,7 @@ module.exports = class bybit extends Exchange {
'recent-trading-records',
'funding/prev-funding-rate',
'mark-price-kline',
+ 'risk-limit',
],
},
'privateLinear': {
@@ -132,24 +149,26 @@ module.exports = class bybit extends Exchange {
'stop-order/list',
'stop-order/search',
'position/list',
- 'position/set-auto-add-margin',
- 'position/set-leverage',
- 'position/switch-isolated',
- 'position/trading-stop',
- 'position/add-margin',
'trade/execution/list',
'trade/closed-pnl/list',
- 'risk-limit',
'funding/prev-funding',
'funding/predicted-funding',
],
'post': [
'order/create',
'order/cancel',
- 'order/cancelAll',
+ 'order/cancel-all',
+ 'order/replace',
'stop-order/create',
'stop-order/cancel',
- 'stop-order/cancelAll',
+ 'stop-order/cancel-all',
+ 'stop-order/replace',
+ 'position/switch-isolated',
+ 'position/set-auto-add-margin',
+ 'tpsl/switch-mode',
+ 'position/set-leverage',
+ 'position/trading-stop',
+ 'position/add-margin',
],
},
'position': {
@@ -159,7 +178,7 @@ module.exports = class bybit extends Exchange {
},
'user': {
'get': [
- 'leverage',
+ 'leverage', // deprecated
],
'post': [
'leverage/save',
@@ -259,17 +278,19 @@ module.exports = class bybit extends Exchange {
},
'broad': {
'unknown orderInfo': OrderNotFound, // {"ret_code":-1,"ret_msg":"unknown orderInfo","ext_code":"","ext_info":"","result":null,"time_now":"1584030414.005545","rate_limit_status":99,"rate_limit_reset_ms":1584030414003,"rate_limit":100}
+ 'invalid api_key': AuthenticationError, // {"ret_code":10003,"ret_msg":"invalid api_key","ext_code":"","ext_info":"","result":null,"time_now":"1599547085.415797"}
},
},
'precisionMode': TICK_SIZE,
'options': {
'marketTypes': {
'BTC/USDT': 'linear',
+ 'ETH/USDT': 'linear',
+ 'LTC/USDT': 'linear',
+ 'XTZ/USDT': 'linear',
+ 'LINK/USDT': 'linear',
},
'code': 'BTC',
- 'fetchBalance': {
- 'code': 'BTC',
- },
'cancelAllOrders': {
'method': 'privatePostOrderCancelAll', // privatePostStopOrderCancelAll
},
@@ -298,8 +319,8 @@ module.exports = class bybit extends Exchange {
return this.milliseconds () - this.options['timeDifference'];
}
- async loadTimeDifference () {
- const serverTime = await this.fetchTime ();
+ async loadTimeDifference (params = {}) {
+ const serverTime = await this.fetchTime (params);
const after = this.milliseconds ();
this.options['timeDifference'] = after - serverTime;
return this.options['timeDifference'];
@@ -347,32 +368,66 @@ module.exports = class bybit extends Exchange {
// time_now: '1583930495.454196'
// }
//
+ // sandbox/testnet
+ //
+ // {
+ // "ret_code":0,
+ // "ret_msg":"OK",
+ // "ext_code":"",
+ // "ext_info":"",
+ // "result":[
+ // {
+ // "symbol":"BTCUSD",
+ // "symbol_alias":"BTCUSD",
+ // "status":"Trading",
+ // "base_currency":"BTC",
+ // "quote_currency":"USD",
+ // "price_scale":2,
+ // "taker_fee":"0.00075",
+ // "maker_fee":"-0.00025",
+ // "leverage_filter":{"min_leverage":1,"max_leverage":100,"leverage_step":"0.01"},
+ // "price_filter":{"min_price":"0.5","max_price":"999999.5","tick_size":"0.5"},
+ // "lot_size_filter":{"max_trading_qty":1000000,"min_trading_qty":1,"qty_step":1}
+ // }
+ // ],
+ // "time_now":"1605916574.118500"
+ // }
+ //
const markets = this.safeValue (response, 'result', []);
const options = this.safeValue (this.options, 'fetchMarkets', {});
const linearQuoteCurrencies = this.safeValue (options, 'linear', { 'USDT': true });
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
- const id = this.safeString (market, 'name');
+ const id = this.safeString2 (market, 'name', 'symbol');
const baseId = this.safeString (market, 'base_currency');
const quoteId = this.safeString (market, 'quote_currency');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const linear = (quote in linearQuoteCurrencies);
const inverse = !linear;
- const symbol = base + '/' + quote;
+ let symbol = base + '/' + quote;
+ const baseQuote = base + quote;
+ if (baseQuote !== id) {
+ symbol = id;
+ }
const lotSizeFilter = this.safeValue (market, 'lot_size_filter', {});
const priceFilter = this.safeValue (market, 'price_filter', {});
const precision = {
'amount': this.safeFloat (lotSizeFilter, 'qty_step'),
'price': this.safeFloat (priceFilter, 'tick_size'),
};
+ const status = this.safeString (market, 'status');
+ let active = undefined;
+ if (status !== undefined) {
+ active = (status === 'Trading');
+ }
result.push ({
'id': id,
'symbol': symbol,
'base': base,
'quote': quote,
- 'active': undefined,
+ 'active': active,
'precision': precision,
'taker': this.safeFloat (market, 'taker_fee'),
'maker': this.safeFloat (market, 'maker_fee'),
@@ -404,13 +459,15 @@ module.exports = class bybit extends Exchange {
async fetchBalance (params = {}) {
await this.loadMarkets ();
- const defaultCode = this.safeValue (this.options, 'code', 'BTC');
- const options = this.safeValue (this.options, 'fetchBalance', {});
- const code = this.safeValue (options, 'code', defaultCode);
- const currency = this.currency (code);
- const request = {
- 'coin': currency['id'],
- };
+ const request = {};
+ const coin = this.safeString (params, 'coin');
+ const code = this.safeString (params, 'code');
+ if (coin !== undefined) {
+ request['coin'] = coin;
+ } else if (code !== undefined) {
+ const currency = this.currency (code);
+ request['coin'] = currency['id'];
+ }
const response = await this.privateGetWalletBalance (this.extend (request, params));
//
// {
@@ -491,13 +548,7 @@ module.exports = class bybit extends Exchange {
//
const timestamp = undefined;
const marketId = this.safeString (ticker, 'symbol');
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const last = this.safeFloat (ticker, 'last_price');
const open = this.safeFloat (ticker, 'prev_price_24h');
let percentage = this.safeFloat (ticker, 'price_24h_pcnt');
@@ -512,10 +563,7 @@ module.exports = class bybit extends Exchange {
}
const baseVolume = this.safeFloat (ticker, 'turnover_24h');
const quoteVolume = this.safeFloat (ticker, 'volume_24h');
- let vwap = undefined;
- if (quoteVolume !== undefined && baseVolume !== undefined) {
- vwap = quoteVolume / baseVolume;
- }
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -641,7 +689,9 @@ module.exports = class bybit extends Exchange {
return this.filterByArray (tickers, 'symbol', symbols);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // inverse perpetual BTC/USD
//
// {
// symbol: 'BTCUSD',
@@ -653,7 +703,9 @@ module.exports = class bybit extends Exchange {
// close: '7763.5',
// volume: '1259766',
// turnover: '162.32773718999994'
- // },
+ // }
+ //
+ // linear perpetual BTC/USDT
//
// {
// "id":143536,
@@ -796,30 +848,12 @@ module.exports = class bybit extends Exchange {
// }
//
const id = this.safeString2 (trade, 'id', 'exec_id');
- let symbol = undefined;
- let base = undefined;
const marketId = this.safeString (trade, 'symbol');
- let amount = this.safeFloat2 (trade, 'qty', 'exec_qty');
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
+ const amount = this.safeFloat2 (trade, 'qty', 'exec_qty');
let cost = this.safeFloat (trade, 'exec_value');
- const price = this.safeFloat2 (trade, 'price', 'exec_price');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- base = market['base'];
- }
- if (market !== undefined) {
- if (symbol === undefined) {
- symbol = market['symbol'];
- base = market['base'];
- }
- // if private trade
- if ('exec_fee' in trade) {
- if (market['inverse']) {
- amount = this.safeFloat (trade, 'exec_value');
- cost = this.safeFloat (trade, 'exec_qty');
- }
- }
- }
+ const price = this.safeFloat2 (trade, 'exec_price', 'price');
if (cost === undefined) {
if (amount !== undefined) {
if (price !== undefined) {
@@ -837,9 +871,10 @@ module.exports = class bybit extends Exchange {
const feeCost = this.safeFloat (trade, 'exec_fee');
let fee = undefined;
if (feeCost !== undefined) {
+ const feeCurrencyCode = market['inverse'] ? market['base'] : market['quote'];
fee = {
'cost': feeCost,
- 'currency': base,
+ 'currency': feeCurrencyCode,
'rate': this.safeFloat (trade, 'fee_rate'),
};
}
@@ -956,11 +991,11 @@ module.exports = class bybit extends Exchange {
'Rejected': 'rejected', // order is triggered but failed upon being placed
'New': 'open',
'PartiallyFilled': 'open',
- 'Filled': 'filled',
+ 'Filled': 'closed',
'Cancelled': 'canceled',
'PendingCancel': 'canceling', // the engine has received the cancellation but there is no guarantee that it will be successful
// conditional orders
- 'Active': 'closed', // order is triggered and placed successfully
+ 'Active': 'open', // order is triggered and placed successfully
'Untriggered': 'open', // order waits to be triggered
'Triggered': 'closed', // order is triggered
// 'Cancelled': 'canceled', // order is cancelled
@@ -970,6 +1005,16 @@ module.exports = class bybit extends Exchange {
return this.safeString (statuses, status, status);
}
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'GoodTillCancel': 'GTC',
+ 'ImmediateOrCancel': 'IOC',
+ 'FillOrKill': 'FOK',
+ 'PostOnly': 'PO',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
+ }
+
parseOrder (order, market = undefined) {
//
// createOrder
@@ -1026,34 +1071,60 @@ module.exports = class bybit extends Exchange {
// "order_id" : "dd2504b9-0157-406a-99e1-efa522373944"
// }
//
+ // conditional order
+ //
+ // {
+ // "user_id":##,
+ // "symbol":"BTCUSD",
+ // "side":"Buy",
+ // "order_type":"Market",
+ // "price":0,
+ // "qty":10,
+ // "time_in_force":"GoodTillCancel",
+ // "stop_order_type":"Stop",
+ // "trigger_by":"LastPrice",
+ // "base_price":11833,
+ // "order_status":"Untriggered",
+ // "ext_fields":{
+ // "stop_order_type":"Stop",
+ // "trigger_by":"LastPrice",
+ // "base_price":11833,
+ // "expected_direction":"Rising",
+ // "trigger_price":12400,
+ // "close_on_trigger":true,
+ // "op_from":"api",
+ // "remark":"145.53.159.48",
+ // "o_req_num":0
+ // },
+ // "leaves_qty":10,
+ // "leaves_value":0.00080645,
+ // "reject_reason":null,
+ // "cross_seq":-1,
+ // "created_at":"2020-08-21T09:18:48.000Z",
+ // "updated_at":"2020-08-21T09:18:48.000Z",
+ // "stop_px":12400,
+ // "stop_order_id":"3f3b54b1-3379-42c7-8510-44f4d9915be0"
+ // }
+ //
const marketId = this.safeString (order, 'symbol');
+ market = this.safeMarket (marketId, market);
let symbol = undefined;
let base = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
- const id = this.safeString (order, 'order_id');
- const price = this.safeFloat (order, 'price');
- const average = this.safeFloat (order, 'average_price');
- let amount = undefined;
- let cost = undefined;
- let filled = undefined;
- let remaining = undefined;
+ const id = this.safeString2 (order, 'order_id', 'stop_order_id');
+ const type = this.safeStringLower (order, 'order_type');
+ let price = this.safeFloat (order, 'price');
+ if (price === 0.0) {
+ price = undefined;
+ }
+ let average = this.safeFloat (order, 'average_price');
+ const amount = this.safeFloat (order, 'qty');
+ let cost = this.safeFloat (order, 'cum_exec_value');
+ let filled = this.safeFloat (order, 'cum_exec_qty');
+ let remaining = this.safeFloat (order, 'leaves_qty');
if (market !== undefined) {
symbol = market['symbol'];
base = market['base'];
- if (market['inverse']) {
- cost = this.safeFloat (order, 'cum_exec_qty');
- filled = this.safeFloat (order, 'cum_exec_value');
- remaining = this.safeFloat (order, 'leaves_value');
- amount = this.sum (filled, remaining);
- } else {
- amount = this.safeFloat (order, 'qty');
- cost = this.safeFloat (order, 'cum_exec_value');
- filled = this.safeFloat (order, 'cum_exec_qty');
- remaining = this.safeFloat (order, 'leaves_qty');
- }
}
let lastTradeTimestamp = this.safeTimestamp (order, 'last_exec_time');
if (lastTradeTimestamp === 0) {
@@ -1071,8 +1142,14 @@ module.exports = class bybit extends Exchange {
cost = price * filled;
}
}
+ if ((type === 'market') && (cost !== undefined) && (cost > 0)) {
+ price = undefined;
+ if (average === undefined) {
+ average = filled / cost;
+ }
+ }
}
- const status = this.parseOrderStatus (this.safeString (order, 'order_status'));
+ const status = this.parseOrderStatus (this.safeString2 (order, 'order_status', 'stop_order_status'));
const side = this.safeStringLower (order, 'side');
let feeCost = this.safeFloat (order, 'cum_exec_fee');
let fee = undefined;
@@ -1083,11 +1160,12 @@ module.exports = class bybit extends Exchange {
'currency': base,
};
}
- const type = this.safeStringLower (order, 'order_type');
let clientOrderId = this.safeString (order, 'order_link_id');
if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
clientOrderId = undefined;
}
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'time_in_force'));
+ const stopPrice = this.safeFloat (order, 'stop_px');
return {
'info': order,
'id': id,
@@ -1097,8 +1175,10 @@ module.exports = class bybit extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -1209,20 +1289,26 @@ module.exports = class bybit extends Exchange {
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
+ let qty = this.amountToPrecision (symbol, amount);
+ if (market['inverse']) {
+ qty = parseInt (qty);
+ } else {
+ qty = parseFloat (qty);
+ }
const request = {
// orders ---------------------------------------------------------
'side': this.capitalize (side),
'symbol': market['id'],
'order_type': this.capitalize (type),
- 'qty': this.amountToPrecision (symbol, amount), // order quantity in USD, integer only
- // 'price': this.priceToPrecision (symbol, price), // required for limit orders
+ 'qty': qty, // order quantity in USD, integer only
+ // 'price': parseFloat (this.priceToPrecision (symbol, price)), // required for limit orders
'time_in_force': 'GoodTillCancel', // ImmediateOrCancel, FillOrKill, PostOnly
// 'take_profit': 123.45, // take profit price, only take effect upon opening the position
// 'stop_loss': 123.45, // stop loss price, only take effect upon opening the position
- // 'reduce_only': false, // reduce only
+ // 'reduce_only': false, // reduce only, required for linear orders
// when creating a closing order, bybit recommends a True value for
// close_on_trigger to avoid failing due to insufficient available margin
- // 'close_on_trigger': false,
+ // 'close_on_trigger': false, required for linear orders
// 'order_link_id': 'string', // unique client order id, max 36 characters
// conditional orders ---------------------------------------------
// base_price is used to compare with the value of stop_px, to decide
@@ -1239,24 +1325,34 @@ module.exports = class bybit extends Exchange {
}
if (priceIsRequired) {
if (price !== undefined) {
- request['price'] = this.priceToPrecision (symbol, price);
+ request['price'] = parseFloat (this.priceToPrecision (symbol, price));
} else {
throw new ArgumentsRequired (this.id + ' createOrder requires a price argument for a ' + type + ' order');
}
}
- const stopPx = this.safeValue (params, 'stop_px');
+ const clientOrderId = this.safeString2 (params, 'order_link_id', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['order_link_id'] = clientOrderId;
+ params = this.omit (params, [ 'order_link_id', 'clientOrderId' ]);
+ }
+ const stopPx = this.safeValue2 (params, 'stop_px', 'stopPrice');
const basePrice = this.safeValue (params, 'base_price');
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
let method = (marketType === 'linear') ? 'privateLinearPostOrderCreate' : 'privatePostOrderCreate';
+ if (marketType === 'linear') {
+ method = 'privateLinearPostOrderCreate';
+ request['reduce_only'] = false;
+ request['close_on_trigger'] = false;
+ }
if (stopPx !== undefined) {
if (basePrice === undefined) {
throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order');
} else {
method = (marketType === 'linear') ? 'privateLinearPostStopOrderCreate' : 'openapiPostStopOrderCreate';
- request['stop_px'] = this.priceToPrecision (symbol, stopPx);
- request['base_price'] = this.priceToPrecision (symbol, basePrice);
- params = this.omit (params, [ 'stop_px', 'base_price' ]);
+ request['stop_px'] = parseFloat (this.priceToPrecision (symbol, stopPx));
+ request['base_price'] = parseFloat (this.priceToPrecision (symbol, basePrice));
+ params = this.omit (params, [ 'stop_px', 'stopPrice', 'base_price' ]);
}
} else if (basePrice !== undefined) {
throw new ArgumentsRequired (this.id + ' createOrder requires both the stop_px and base_price params for a conditional ' + type + ' order');
@@ -1349,9 +1445,6 @@ module.exports = class bybit extends Exchange {
}
const marketTypes = this.safeValue (this.options, 'marketTypes', {});
const marketType = this.safeString (marketTypes, symbol);
- if (marketType === 'linear') {
- throw new NotSupported (this.id + ' does not support editOrder for ' + marketType + ' ' + symbol + ' market type');
- }
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
@@ -1364,20 +1457,20 @@ module.exports = class bybit extends Exchange {
// 'stop_order_id': id, // only for conditional orders
// 'p_r_trigger_price': 123.45, // new trigger price also known as stop_px
};
+ let method = (marketType === 'linear') ? 'privateLinearPostOrderReplace' : 'openapiPostOrderReplace';
const stopOrderId = this.safeString (params, 'stop_order_id');
- let method = 'openapiPostOrderReplace';
if (stopOrderId !== undefined) {
- method = 'openapiPostStopOrderReplace';
+ method = (marketType === 'linear') ? 'privateLinearPostStopOrderReplace' : 'openapiPostStopOrderReplace';
request['stop_order_id'] = stopOrderId;
params = this.omit (params, [ 'stop_order_id' ]);
} else {
request['order_id'] = id;
}
if (amount !== undefined) {
- request['p_r_qty'] = this.amountToPrecision (symbol, amount);
+ request['p_r_qty'] = parseInt (this.amountToPrecision (symbol, amount));
}
if (price !== undefined) {
- request['p_r_price'] = this.priceToPrecision (symbol, price);
+ request['p_r_price'] = parseFloat (this.priceToPrecision (symbol, price));
}
const response = await this[method] (this.extend (request, params));
//
@@ -1417,7 +1510,7 @@ module.exports = class bybit extends Exchange {
async cancelOrder (id, symbol = undefined, params = {}) {
if (symbol === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
}
await this.loadMarkets ();
const market = this.market (symbol);
@@ -1687,6 +1780,8 @@ module.exports = class bybit extends Exchange {
const method = (marketType === 'linear') ? 'privateLinearGetTradeExecutionList' : 'privateGetExecutionList';
const response = await this[method] (this.extend (request, params));
//
+ // inverse
+ //
// {
// "ret_code": 0,
// "ret_msg": "OK",
@@ -1726,8 +1821,48 @@ module.exports = class bybit extends Exchange {
// "rate_limit": 120
// }
//
+ // linear
+ //
+ // {
+ // "ret_code":0,
+ // "ret_msg":"OK",
+ // "ext_code":"",
+ // "ext_info":"",
+ // "result":{
+ // "current_page":1,
+ // "data":[
+ // {
+ // "order_id":"b59418ec-14d4-4ef9-b9f4-721d5d576974",
+ // "order_link_id":"",
+ // "side":"Sell",
+ // "symbol":"BTCUSDT",
+ // "exec_id":"0327284d-faec-5191-bd89-acc5b4fafda9",
+ // "price":0.5,
+ // "order_price":0.5,
+ // "order_qty":0.01,
+ // "order_type":"Market",
+ // "fee_rate":0.00075,
+ // "exec_price":9709.5,
+ // "exec_type":"Trade",
+ // "exec_qty":0.01,
+ // "exec_fee":0.07282125,
+ // "exec_value":97.095,
+ // "leaves_qty":0,
+ // "closed_size":0.01,
+ // "last_liquidity_ind":"RemovedLiquidity",
+ // "trade_time":1591648052,
+ // "trade_time_ms":1591648052861
+ // }
+ // ]
+ // },
+ // "time_now":"1591736501.979264",
+ // "rate_limit_status":119,
+ // "rate_limit_reset_ms":1591736501974,
+ // "rate_limit":120
+ // }
+ //
const result = this.safeValue (response, 'result', {});
- const trades = this.safeValue (result, 'trade_list', []);
+ const trades = this.safeValue2 (result, 'trade_list', 'data', []);
return this.parseTrades (trades, market, since, limit);
}
@@ -2044,7 +2179,13 @@ module.exports = class bybit extends Exchange {
'recv_window': this.options['recvWindow'],
'timestamp': timestamp,
});
- const auth = this.rawencode (this.keysort (query));
+ let auth = this.rawencode (this.keysort (query));
+ // https://github.com/ccxt/ccxt/issues/7377
+ // https://github.com/ccxt/ccxt/issues/7515
+ // bybit encodes whole floats as integers without .0 for conditional stop-orders only
+ if (path.indexOf ('stop-order') >= 0) {
+ auth = auth.replace ('.0&', '&');
+ }
const signature = this.hmac (this.encode (auth), this.encode (this.secret));
if (method === 'POST') {
body = this.json (this.extend (query, {
diff --git a/TaskServer/node_modules/ccxt/js/bytetrade.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bytetrade.js
similarity index 94%
rename from TaskServer/node_modules/ccxt/js/bytetrade.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bytetrade.js
index b0d50b5cc..bbd1af6f6 100644
--- a/TaskServer/node_modules/ccxt/js/bytetrade.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/bytetrade.js
@@ -19,20 +19,27 @@ module.exports = class bytetrade extends Exchange {
'certified': true,
// new metainfo interface
'has': {
+ 'cancelOrder': true,
+ 'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchBidsAsks': true,
+ 'fetchClosedOrders': true,
'fetchCurrencies': true,
'fetchDepositAddress': true,
- 'CORS': false,
- 'fetchBidsAsks': true,
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchMyTrades': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'withdraw': true,
'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1m',
@@ -53,11 +60,11 @@ module.exports = class bytetrade extends Exchange {
},
'logo': 'https://user-images.githubusercontent.com/1294454/67288762-2f04a600-f4e6-11e9-9fd6-c60641919491.jpg',
'api': {
- 'market': 'https://api-v2.bytetrade.com',
- 'public': 'https://api-v2.bytetrade.com',
+ 'market': 'https://api-v2.byte-trade.com',
+ 'public': 'https://api-v2.byte-trade.com',
},
'www': 'https://www.byte-trade.com',
- 'doc': 'https://github.com/Bytetrade/bytetrade-official-api-docs/wiki',
+ 'doc': 'https://docs.byte-trade.com/#description',
},
'api': {
'market': {
@@ -98,8 +105,10 @@ module.exports = class bytetrade extends Exchange {
},
},
'commonCurrencies': {
+ '1': 'ByteTrade',
'44': 'ByteHub',
'48': 'Blocktonic',
+ '133': 'TerraCredit',
},
'exceptions': {
'vertify error': AuthenticationError, // typo on the exchange side, 'vertify'
@@ -191,10 +200,7 @@ module.exports = class bytetrade extends Exchange {
'code': code,
'name': name,
'active': active,
- 'precision': {
- 'amount': amountPrecision,
- 'price': undefined,
- },
+ 'precision': amountPrecision,
'fee': undefined,
'limits': {
'amount': { 'min': undefined, 'max': undefined },
@@ -223,11 +229,14 @@ module.exports = class bytetrade extends Exchange {
const id = this.safeString (market, 'symbol');
let base = this.safeString (market, 'baseName');
let quote = this.safeString (market, 'quoteName');
- const normalBase = base.split ('@')[0];
- const normalQuote = quote.split ('@')[0];
- const normalSymbol = normalBase + '/' + normalQuote;
const baseId = this.safeString (market, 'base');
const quoteId = this.safeString (market, 'quote');
+ const normalBase = base.split ('@' + baseId)[0];
+ let normalQuote = quote.split ('@' + quoteId)[0];
+ if (quoteId === '126') {
+ normalQuote = 'ZAR'; // The id 126 coin is a special coin whose name on the chain is actually ZAR, but it is changed to ZCN after creation, so it must be changed to ZAR when placing the transaction in the chain
+ }
+ const normalSymbol = normalBase + '/' + normalQuote;
if (baseId in this.commonCurrencies) {
base = this.commonCurrencies[baseId];
}
@@ -432,14 +441,24 @@ module.exports = class bytetrade extends Exchange {
return this.parseTickers (rawTickers, symbols);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591505760000,
+ // "242.7",
+ // "242.76",
+ // "242.69",
+ // "242.76",
+ // "0.1892"
+ // ]
+ //
return [
- ohlcv[0],
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
- parseFloat (ohlcv[5]),
+ this.safeInteger (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -457,6 +476,13 @@ module.exports = class bytetrade extends Exchange {
request['limit'] = limit;
}
const response = await this.marketGetKlines (this.extend (request, params));
+ //
+ // [
+ // [1591505760000,"242.7","242.76","242.69","242.76","0.1892"],
+ // [1591505820000,"242.77","242.83","242.7","242.72","0.6378"],
+ // [1591505880000,"242.72","242.73","242.61","242.72","0.4141"],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -469,7 +495,7 @@ module.exports = class bytetrade extends Exchange {
const type = this.safeString (trade, 'type');
const takerOrMaker = this.safeString (trade, 'takerOrMaker');
const side = this.safeString (trade, 'side');
- const datetime = this.safeString (trade, 'datetime');
+ const datetime = this.iso8601 (timestamp); // this.safeString (trade, 'datetime');
const order = this.safeString (trade, 'order');
const fee = this.safeValue (trade, 'fee');
let symbol = undefined;
@@ -553,8 +579,10 @@ module.exports = class bytetrade extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'average': average,
@@ -590,11 +618,11 @@ module.exports = class bytetrade extends Exchange {
const baseId = market['baseId'];
const baseCurrency = this.currency (market['base']);
const amountTruncated = this.amountToPrecision (symbol, amount);
- const amountChain = this.toWei (amountTruncated, baseCurrency['precision']['amount']);
+ const amountChain = this.toWei (amountTruncated, baseCurrency['precision']);
const quoteId = market['quoteId'];
const quoteCurrency = this.currency (market['quote']);
const priceRounded = this.priceToPrecision (symbol, price);
- const priceChain = this.toWei (priceRounded, quoteCurrency['precision']['amount']);
+ const priceChain = this.toWei (priceRounded, quoteCurrency['precision']);
const now = this.milliseconds ();
const expiration = this.milliseconds ();
let datetime = this.iso8601 (now);
@@ -604,6 +632,8 @@ module.exports = class bytetrade extends Exchange {
const defaultDappId = 'Sagittarius';
const dappId = this.safeString (params, 'dappId', defaultDappId);
const defaultFee = this.safeString (this.options, 'fee', '300000000000000');
+ const totalFeeRate = this.safeString (params, 'totalFeeRate', 8);
+ const chainFeeRate = this.safeString (params, 'chainFeeRate', 1);
const fee = this.safeString (params, 'fee', defaultFee);
const eightBytes = this.integerPow ('2', '64');
const allByteStringArray = [
@@ -628,7 +658,10 @@ module.exports = class bytetrade extends Exchange {
this.numberToLE (0, 2),
this.numberToLE (Math.floor (now / 1000), 4),
this.numberToLE (Math.floor (expiration / 1000), 4),
- this.numberToLE (0, 2),
+ this.numberToLE (1, 1),
+ this.numberToLE (parseInt (chainFeeRate), 2),
+ this.numberToLE (1, 1),
+ this.numberToLE (parseInt (totalFeeRate), 2),
this.numberToLE (parseInt (quoteId), 4),
this.numberToLE (parseInt (baseId), 4),
this.numberToLE (0, 1),
@@ -658,7 +691,10 @@ module.exports = class bytetrade extends Exchange {
this.numberToLE (0, 2),
this.numberToLE (Math.floor (now / 1000), 4),
this.numberToLE (Math.floor (expiration / 1000), 4),
- this.numberToLE (0, 2),
+ this.numberToLE (1, 1),
+ this.numberToLE (parseInt (chainFeeRate), 2),
+ this.numberToLE (1, 1),
+ this.numberToLE (parseInt (totalFeeRate), 2),
this.numberToLE (parseInt (quoteId), 4),
this.numberToLE (parseInt (baseId), 4),
this.numberToLE (0, 1),
@@ -681,7 +717,7 @@ module.exports = class bytetrade extends Exchange {
const bytestring = this.binaryConcatArray (allByteStringArray);
const hash = this.hash (bytestring, 'sha256', 'hex');
const signature = this.ecdsa (hash, this.secret, 'secp256k1', undefined, true);
- const recoveryParam = this.decode (this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1)));
+ const recoveryParam = this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1));
const mySignature = recoveryParam + signature['r'] + signature['s'];
const operation = {
'now': datetime,
@@ -696,6 +732,8 @@ module.exports = class bytetrade extends Exchange {
'use_btt_as_fee': false,
'money_id': parseInt (quoteId),
'stock_id': parseInt (baseId),
+ 'custom_no_btt_fee_rate': parseInt (totalFeeRate),
+ 'custom_btt_fee_rate': parseInt (chainFeeRate),
};
const fatty = {
'timestamp': datetime,
@@ -865,7 +903,7 @@ module.exports = class bytetrade extends Exchange {
const bytestring = this.binaryConcatArray (byteStringArray);
const hash = this.hash (bytestring, 'sha256', 'hex');
const signature = this.ecdsa (hash, this.secret, 'secp256k1', undefined, true);
- const recoveryParam = this.decode (this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1)));
+ const recoveryParam = this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1));
const mySignature = recoveryParam + signature['r'] + signature['s'];
const operation = {
'fee': feeAmount,
@@ -926,8 +964,8 @@ module.exports = class bytetrade extends Exchange {
}
await this.loadMarkets ();
const currency = this.currency (code);
- const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING);
- const amountChain = this.toWei (amountTruncate, currency['precision']['amount']);
+ const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['basePrecision'] - currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING);
+ const amountChain = this.toWei (amountTruncate, currency['precision']);
const assetType = parseInt (currency['id']);
const now = this.milliseconds ();
const expiration = now;
@@ -967,7 +1005,7 @@ module.exports = class bytetrade extends Exchange {
const bytestring = this.binaryConcatArray (byteStringArray);
const hash = this.hash (bytestring, 'sha256', 'hex');
const signature = this.ecdsa (hash, this.secret, 'secp256k1', undefined, true);
- const recoveryParam = this.decode (this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1)));
+ const recoveryParam = this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1));
const mySignature = recoveryParam + signature['r'] + signature['s'];
const operation = {
'fee': '300000000000000',
@@ -1207,7 +1245,7 @@ module.exports = class bytetrade extends Exchange {
const feeAmount = '300000000000000';
const currency = this.currency (code);
const coinId = currency['id'];
- const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING);
+ const amountTruncate = this.decimalToPrecision (amount, TRUNCATE, currency['info']['basePrecision'] - currency['info']['transferPrecision'], DECIMAL_PLACES, NO_PADDING);
const amountChain = this.toWei (amountTruncate, currency['info']['externalPrecision']);
const eightBytes = this.integerPow ('2', '64');
let assetFee = 0;
@@ -1273,7 +1311,7 @@ module.exports = class bytetrade extends Exchange {
const bytestring = this.binaryConcatArray (byteStringArray);
const hash = this.hash (bytestring, 'sha256', 'hex');
const signature = this.ecdsa (hash, this.secret, 'secp256k1', undefined, true);
- const recoveryParam = this.decode (this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1)));
+ const recoveryParam = this.binaryToBase16 (this.numberToLE (this.sum (signature['v'], 31), 1));
const mySignature = recoveryParam + signature['r'] + signature['s'];
let fatty = undefined;
let request = undefined;
diff --git a/TaskServer/node_modules/ccxt/js/cex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/cex.js
similarity index 89%
rename from TaskServer/node_modules/ccxt/js/cex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/cex.js
index dd8ab9391..082db07c7 100644
--- a/TaskServer/node_modules/ccxt/js/cex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/cex.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, AuthenticationError, NullResponse, InvalidOrder, NotSupported, InsufficientFunds, InvalidNonce, OrderNotFound, RateLimitExceeded } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, AuthenticationError, NullResponse, InvalidOrder, NotSupported, InsufficientFunds, InvalidNonce, OrderNotFound, RateLimitExceeded, DDoSProtection } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -15,15 +15,23 @@ module.exports = class cex extends Exchange {
'countries': [ 'GB', 'EU', 'CY', 'RU' ],
'rateLimit': 1500,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchCurrencies': true,
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
'fetchDepositAddress': true,
+ 'fetchMarkets': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'timeframes': {
'1m': '1m',
@@ -125,9 +133,10 @@ module.exports = class cex extends Exchange {
'Nonce must be incremented': InvalidNonce,
'Invalid Order': InvalidOrder,
'Order not found': OrderNotFound,
- 'Rate limit exceeded': RateLimitExceeded,
+ 'limit exceeded': RateLimitExceeded, // {"error":"rate limit exceeded"}
'Invalid API key': AuthenticationError,
'There was an error while placing your order': InvalidOrder,
+ 'Sorry, too many clients already': DDoSProtection,
},
},
'options': {
@@ -137,7 +146,7 @@ module.exports = class cex extends Exchange {
'status': {
'c': 'canceled',
'd': 'closed',
- 'cd': 'closed',
+ 'cd': 'canceled',
'a': 'open',
},
},
@@ -393,14 +402,24 @@ module.exports = class cex extends Exchange {
return this.parseOrderBook (response, timestamp);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591403940,
+ // 0.024972,
+ // 0.024972,
+ // 0.024969,
+ // 0.024969,
+ // 0.49999900
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- ohlcv[1],
- ohlcv[2],
- ohlcv[3],
- ohlcv[4],
- ohlcv[5],
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -423,8 +442,15 @@ module.exports = class cex extends Exchange {
};
try {
const response = await this.publicGetOhlcvHdYyyymmddPair (this.extend (request, params));
+ //
+ // {
+ // "time":20200606,
+ // "data1m":"[[1591403940,0.024972,0.024972,0.024969,0.024969,0.49999900]]",
+ // }
+ //
const key = 'data' + this.timeframes[timeframe];
- const ohlcvs = JSON.parse (response[key]);
+ const data = this.safeString (response, key);
+ const ohlcvs = JSON.parse (data);
return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
} catch (e) {
if (e instanceof NullResponse) {
@@ -484,7 +510,7 @@ module.exports = class cex extends Exchange {
const market = this.markets[symbol];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -856,8 +882,10 @@ module.exports = class cex extends Exchange {
'status': status,
'symbol': symbol,
'type': (price === undefined) ? 'market' : 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -904,7 +932,108 @@ module.exports = class cex extends Exchange {
'id': id.toString (),
};
const response = await this.privatePostGetOrderTx (this.extend (request, params));
- return this.parseOrder (response['data']);
+ const data = this.safeValue (response, 'data', {});
+ //
+ // {
+ // "id": "5442731603",
+ // "type": "sell",
+ // "time": 1516132358071,
+ // "lastTxTime": 1516132378452,
+ // "lastTx": "5442734452",
+ // "pos": null,
+ // "user": "up106404164",
+ // "status": "d",
+ // "symbol1": "ETH",
+ // "symbol2": "EUR",
+ // "amount": "0.50000000",
+ // "kind": "api",
+ // "price": "923.3386",
+ // "tfacf": "1",
+ // "fa:EUR": "0.55",
+ // "ta:EUR": "369.77",
+ // "remains": "0.00000000",
+ // "tfa:EUR": "0.22",
+ // "tta:EUR": "91.95",
+ // "a:ETH:cds": "0.50000000",
+ // "a:EUR:cds": "461.72",
+ // "f:EUR:cds": "0.77",
+ // "tradingFeeMaker": "0.15",
+ // "tradingFeeTaker": "0.23",
+ // "tradingFeeStrategy": "userVolumeAmount",
+ // "tradingFeeUserVolumeAmount": "2896912572",
+ // "orderId": "5442731603",
+ // "next": false,
+ // "vtx": [
+ // {
+ // "id": "5442734452",
+ // "type": "sell",
+ // "time": "2018-01-16T19:52:58.452Z",
+ // "user": "up106404164",
+ // "c": "user:up106404164:a:EUR",
+ // "d": "order:5442731603:a:EUR",
+ // "a": "104.53000000",
+ // "amount": "104.53000000",
+ // "balance": "932.71000000",
+ // "symbol": "EUR",
+ // "order": "5442731603",
+ // "buy": "5442734443",
+ // "sell": "5442731603",
+ // "pair": null,
+ // "pos": null,
+ // "office": null,
+ // "cs": "932.71",
+ // "ds": 0,
+ // "price": 923.3386,
+ // "symbol2": "ETH",
+ // "fee_amount": "0.16"
+ // },
+ // {
+ // "id": "5442731609",
+ // "type": "sell",
+ // "time": "2018-01-16T19:52:38.071Z",
+ // "user": "up106404164",
+ // "c": "user:up106404164:a:EUR",
+ // "d": "order:5442731603:a:EUR",
+ // "a": "91.73000000",
+ // "amount": "91.73000000",
+ // "balance": "563.49000000",
+ // "symbol": "EUR",
+ // "order": "5442731603",
+ // "buy": "5442618127",
+ // "sell": "5442731603",
+ // "pair": null,
+ // "pos": null,
+ // "office": null,
+ // "cs": "563.49",
+ // "ds": 0,
+ // "price": 924.0092,
+ // "symbol2": "ETH",
+ // "fee_amount": "0.22"
+ // },
+ // {
+ // "id": "5442731604",
+ // "type": "sell",
+ // "time": "2018-01-16T19:52:38.071Z",
+ // "user": "up106404164",
+ // "c": "order:5442731603:a:ETH",
+ // "d": "user:up106404164:a:ETH",
+ // "a": "0.50000000",
+ // "amount": "-0.50000000",
+ // "balance": "15.80995000",
+ // "symbol": "ETH",
+ // "order": "5442731603",
+ // "buy": null,
+ // "sell": null,
+ // "pair": null,
+ // "pos": null,
+ // "office": null,
+ // "cs": "0.50000000",
+ // "ds": "15.80995000"
+ // }
+ // ]
+ // }
+ //
+ return this.parseOrder (data);
}
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
diff --git a/TaskServer/node_modules/ccxt/js/chilebit.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/chilebit.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/chilebit.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/chilebit.js
diff --git a/TaskServer/node_modules/ccxt/js/coinbase.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinbase.js
similarity index 98%
rename from TaskServer/node_modules/ccxt/js/coinbase.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinbase.js
index 86699a90b..61fc650dc 100644
--- a/TaskServer/node_modules/ccxt/js/coinbase.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinbase.js
@@ -141,6 +141,9 @@ module.exports = class coinbase extends Exchange {
'rate_limit_exceeded': RateLimitExceeded, // 429 Rate limit exceeded
'internal_server_error': ExchangeError, // 500 Internal server error
},
+ 'commonCurrencies': {
+ 'CGLD': 'CELO',
+ },
'options': {
'fetchCurrencies': {
'expires': 5000,
@@ -156,8 +159,16 @@ module.exports = class coinbase extends Exchange {
async fetchTime (params = {}) {
const response = await this.publicGetTime (params);
+ //
+ // {
+ // "data": {
+ // "epoch": 1589295679,
+ // "iso": "2020-05-12T15:01:19Z"
+ // }
+ // }
+ //
const data = this.safeValue (response, 'data', {});
- return this.parse8601 (this.safeString (data, 'iso'));
+ return this.safeTimestamp (data, 'epoch');
}
async fetchAccounts (params = {}) {
@@ -459,8 +470,8 @@ module.exports = class coinbase extends Exchange {
const id = this.safeString (trade, 'id');
const timestamp = this.parse8601 (this.safeValue (trade, 'created_at'));
if (market === undefined) {
- const baseId = this.safeString (totalObject, 'currency');
- const quoteId = this.safeString (amountObject, 'currency');
+ const baseId = this.safeString (amountObject, 'currency');
+ const quoteId = this.safeString (totalObject, 'currency');
if ((baseId !== undefined) && (quoteId !== undefined)) {
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
@@ -474,7 +485,7 @@ module.exports = class coinbase extends Exchange {
const amount = this.safeFloat (amountObject, 'amount');
let price = undefined;
if (cost !== undefined) {
- if (amount !== undefined) {
+ if ((amount !== undefined) && (amount > 0)) {
price = cost / amount;
}
}
@@ -722,13 +733,17 @@ module.exports = class coinbase extends Exchange {
async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
const request = await this.prepareAccountRequestWithCurrencyCode (code, limit, params);
const query = this.omit (params, ['account_id', 'accountId']);
// for pagination use parameter 'starting_after'
// the value for the next page can be obtained from the result of the previous call in the 'pagination' field
// eg: instance.last_json_response.pagination.next_starting_after
const response = await this.privateGetAccountsAccountIdTransactions (this.extend (request, query));
- return this.parseLedger (response['data'], undefined, since, limit);
+ return this.parseLedger (response['data'], currency, since, limit);
}
parseLedgerEntryStatus (status) {
diff --git a/TaskServer/node_modules/ccxt/js/coinbaseprime.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinbaseprime.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/coinbaseprime.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinbaseprime.js
diff --git a/TaskServer/node_modules/ccxt/js/coinbasepro.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinbasepro.js
similarity index 78%
rename from TaskServer/node_modules/ccxt/js/coinbasepro.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinbasepro.js
index 7c7db7483..f28b951c4 100644
--- a/TaskServer/node_modules/ccxt/js/coinbasepro.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinbasepro.js
@@ -3,7 +3,8 @@
// ----------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { InsufficientFunds, ArgumentsRequired, ExchangeError, InvalidOrder, InvalidAddress, AuthenticationError, NotSupported, OrderNotFound, OnMaintenance, RateLimitExceeded } = require ('./base/errors');
+const { InsufficientFunds, ArgumentsRequired, ExchangeError, InvalidOrder, InvalidAddress, AuthenticationError, NotSupported, OrderNotFound, OnMaintenance, PermissionDenied, RateLimitExceeded } = require ('./base/errors');
+const { TICK_SIZE } = require ('./base/functions/number');
// ----------------------------------------------------------------------------
@@ -18,21 +19,31 @@ module.exports = class coinbasepro extends Exchange {
'pro': true,
'has': {
'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': true,
+ 'createDepositAddress': true,
+ 'createOrder': true,
'deposit': true,
'fetchAccounts': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': true,
'fetchClosedOrders': true,
- 'fetchDepositAddress': true,
- 'createDepositAddress': true,
+ 'fetchDepositAddress': false, // the exchange does not have this method, only createDepositAddress, see https://github.com/ccxt/ccxt/pull/7405
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
- 'fetchOrderTrades': true,
+ 'fetchOrderBook': true,
'fetchOrders': true,
+ 'fetchOrderTrades': true,
'fetchTime': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
'fetchTransactions': true,
'withdraw': true,
+ 'fetchDeposits': true,
+ 'fetchWithdrawals': true,
},
'timeframes': {
'1m': 60,
@@ -69,6 +80,7 @@ module.exports = class coinbasepro extends Exchange {
'get': [
'currencies',
'products',
+ 'products/{id}',
'products/{id}/book',
'products/{id}/candles',
'products/{id}/stats',
@@ -85,17 +97,32 @@ module.exports = class coinbasepro extends Exchange {
'accounts/{id}/ledger',
'accounts/{id}/transfers',
'coinbase-accounts',
- 'coinbase-accounts/{id}/addresses',
'fills',
'funding',
'fees',
+ 'margin/profile_information',
+ 'margin/buying_power',
+ 'margin/withdrawal_power',
+ 'margin/withdrawal_power_all',
+ 'margin/exit_plan',
+ 'margin/liquidation_history',
+ 'margin/position_refresh_amounts',
+ 'margin/status',
+ 'oracle',
'orders',
'orders/{id}',
+ 'orders/client:{client_oid}',
'otc/orders',
'payment-methods',
'position',
- 'reports/{id}',
+ 'profiles',
+ 'profiles/{id}',
+ 'reports/{report_id}',
+ 'transfers',
+ 'transfers/{transfer_id}',
'users/self/trailing-volume',
+ 'users/self/exchange-limits',
+ 'withdrawals/fee-estimate',
],
'post': [
'conversions',
@@ -106,17 +133,24 @@ module.exports = class coinbasepro extends Exchange {
'orders',
'position/close',
'profiles/margin-transfer',
+ 'profiles/transfer',
'reports',
'withdrawals/coinbase',
+ 'withdrawals/coinbase-account',
'withdrawals/crypto',
'withdrawals/payment-method',
],
'delete': [
'orders',
+ 'orders/client:{client_oid}',
'orders/{id}',
],
},
},
+ 'commonCurrencies': {
+ 'CGLD': 'CELO',
+ },
+ 'precisionMode': TICK_SIZE,
'fees': {
'trading': {
'tierBased': true, // complicated tier system per coin
@@ -154,6 +188,8 @@ module.exports = class coinbasepro extends Exchange {
'Invalid Passphrase': AuthenticationError,
'Invalid order id': InvalidOrder,
'Private rate limit exceeded': RateLimitExceeded,
+ 'Trading pair not available': PermissionDenied,
+ 'Product not found': InvalidOrder,
},
'broad': {
'Order already done': OrderNotFound,
@@ -161,13 +197,108 @@ module.exports = class coinbasepro extends Exchange {
'price too small': InvalidOrder,
'price too precise': InvalidOrder,
'under maintenance': OnMaintenance,
+ 'size is too small': InvalidOrder,
+ 'Cancel only mode': OnMaintenance, // https://github.com/ccxt/ccxt/issues/7690
},
},
});
}
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCurrencies (params);
+ //
+ // [
+ // {
+ // id: 'XTZ',
+ // name: 'Tezos',
+ // min_size: '0.000001',
+ // status: 'online',
+ // message: '',
+ // max_precision: '0.000001',
+ // convertible_to: [],
+ // details: {
+ // type: 'crypto',
+ // symbol: 'Τ',
+ // network_confirmations: 60,
+ // sort_order: 53,
+ // crypto_address_link: 'https://tzstats.com/{{address}}',
+ // crypto_transaction_link: 'https://tzstats.com/{{txId}}',
+ // push_payment_methods: [ 'crypto' ],
+ // group_types: [],
+ // display_name: '',
+ // processing_time_seconds: 0,
+ // min_withdrawal_amount: 1
+ // }
+ // }
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const currency = response[i];
+ const id = this.safeString (currency, 'id');
+ const name = this.safeString (currency, 'name');
+ const code = this.safeCurrencyCode (id);
+ const details = this.safeValue (currency, 'details', {});
+ const precision = this.safeFloat (currency, 'max_precision');
+ const status = this.safeString (currency, 'status');
+ const active = (status === 'online');
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': currency,
+ 'type': this.safeString (details, 'type'),
+ 'name': name,
+ 'active': active,
+ 'fee': undefined,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': this.safeFloat (details, 'min_size'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (details, 'min_withdrawal_amount'),
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ return result;
+ }
+
async fetchMarkets (params = {}) {
const response = await this.publicGetProducts (params);
+ //
+ // [
+ // {
+ // "id":"ZEC-BTC",
+ // "base_currency":"ZEC",
+ // "quote_currency":"BTC",
+ // "base_min_size":"0.01000000",
+ // "base_max_size":"1500.00000000",
+ // "quote_increment":"0.00000100",
+ // "base_increment":"0.00010000",
+ // "display_name":"ZEC/BTC",
+ // "min_market_funds":"0.001",
+ // "max_market_funds":"30",
+ // "margin_enabled":false,
+ // "post_only":false,
+ // "limit_only":false,
+ // "cancel_only":false,
+ // "trading_disabled":false,
+ // "status":"online",
+ // "status_message":""
+ // }
+ // ]
+ //
const result = [];
for (let i = 0; i < response.length; i++) {
const market = response[i];
@@ -182,10 +313,11 @@ module.exports = class coinbasepro extends Exchange {
'max': undefined,
};
const precision = {
- 'amount': this.precisionFromString (this.safeString (market, 'base_increment')),
- 'price': this.precisionFromString (this.safeString (market, 'quote_increment')),
+ 'amount': this.safeFloat (market, 'base_increment'),
+ 'price': this.safeFloat (market, 'quote_increment'),
};
- const active = market['status'] === 'online';
+ const status = this.safeString (market, 'status');
+ const active = (status === 'online');
result.push (this.extend (this.fees['trading'], {
'id': id,
'symbol': symbol,
@@ -400,21 +532,8 @@ module.exports = class coinbasepro extends Exchange {
// }
//
const timestamp = this.parse8601 (this.safeString2 (trade, 'time', 'created_at'));
- let symbol = undefined;
const marketId = this.safeString (trade, 'product_id');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
let feeRate = undefined;
let feeCurrency = undefined;
let takerOrMaker = undefined;
@@ -485,14 +604,24 @@ module.exports = class coinbasepro extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591514160,
+ // 0.02507,
+ // 0.02507,
+ // 0.02507,
+ // 0.02507,
+ // 0.02816506
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- ohlcv[3],
- ohlcv[2],
- ohlcv[1],
- ohlcv[4],
- ohlcv[5],
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -513,12 +642,25 @@ module.exports = class coinbasepro extends Exchange {
request['end'] = this.iso8601 (this.sum ((limit - 1) * granularity * 1000, since));
}
const response = await this.publicGetProductsIdCandles (this.extend (request, params));
+ //
+ // [
+ // [1591514160,0.02507,0.02507,0.02507,0.02507,0.02816506],
+ // [1591514100,0.02507,0.02507,0.02507,0.02507,1.63830323],
+ // [1591514040,0.02505,0.02507,0.02505,0.02507,0.19918178]
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
async fetchTime (params = {}) {
const response = await this.publicGetTime (params);
- return this.parse8601 (this.safeString (response, 'iso'));
+ //
+ // {
+ // "iso":"2020-05-12T08:00:51.504Z",
+ // "epoch":1589270451.504
+ // }
+ //
+ return this.safeTimestamp (response, 'epoch');
}
parseOrderStatus (status) {
@@ -535,19 +677,8 @@ module.exports = class coinbasepro extends Exchange {
parseOrder (order, market = undefined) {
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
- let symbol = undefined;
const marketId = this.safeString (order, 'product_id');
- let quote = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
+ market = this.safeMarket (marketId, market, '-');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
const price = this.safeFloat (order, 'price');
const filled = this.safeFloat (order, 'filled_size');
@@ -565,8 +696,6 @@ module.exports = class coinbasepro extends Exchange {
let feeCurrencyCode = undefined;
if (market !== undefined) {
feeCurrencyCode = market['quote'];
- } else if (quote !== undefined) {
- feeCurrencyCode = quote;
}
fee = {
'cost': feeCost,
@@ -574,9 +703,6 @@ module.exports = class coinbasepro extends Exchange {
'rate': undefined,
};
}
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
const id = this.safeString (order, 'id');
const type = this.safeString (order, 'type');
const side = this.safeString (order, 'side');
@@ -588,10 +714,12 @@ module.exports = class coinbasepro extends Exchange {
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': undefined,
'status': status,
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -769,30 +897,49 @@ module.exports = class coinbasepro extends Exchange {
let currency = undefined;
let id = this.safeString (params, 'id'); // account id
if (id === undefined) {
- if (code === undefined) {
- throw new ArgumentsRequired (this.id + ' fetchTransactions() requires a currency code argument if no account id specified in params');
+ if (code !== undefined) {
+ currency = this.currency (code);
+ const accountsByCurrencyCode = this.indexBy (this.accounts, 'currency');
+ const account = this.safeValue (accountsByCurrencyCode, code);
+ if (account === undefined) {
+ throw new ExchangeError (this.id + ' fetchTransactions() could not find account id for ' + code);
+ }
+ id = account['id'];
}
- currency = this.currency (code);
- const accountsByCurrencyCode = this.indexBy (this.accounts, 'currency');
- const account = this.safeValue (accountsByCurrencyCode, code);
- if (account === undefined) {
- throw new ExchangeError (this.id + ' fetchTransactions() could not find account id for ' + code);
- }
- id = account['id'];
}
- const request = {
- 'id': id,
- };
+ const request = {};
+ if (id !== undefined) {
+ request['id'] = id;
+ }
if (limit !== undefined) {
request['limit'] = limit;
}
- const response = await this.privateGetAccountsIdTransfers (this.extend (request, params));
- for (let i = 0; i < response.length; i++) {
- response[i]['currency'] = code;
+ let response = undefined;
+ if (id === undefined) {
+ response = await this.privateGetTransfers (this.extend (request, params));
+ for (let i = 0; i < response.length; i++) {
+ const account_id = this.safeString (response[i], 'account_id');
+ const account = this.safeValue (this.accountsById, account_id);
+ const code = this.safeString (account, 'currency');
+ response[i]['currency'] = code;
+ }
+ } else {
+ response = await this.privateGetAccountsIdTransfers (this.extend (request, params));
+ for (let i = 0; i < response.length; i++) {
+ response[i]['currency'] = code;
+ }
}
return this.parseTransactions (response, currency, since, limit);
}
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return this.fetchTransactions (code, since, limit, this.extend (params, { 'type': 'deposit' }));
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return this.fetchTransactions (code, since, limit, this.extend (params, { 'type': 'withdraw' }));
+ }
+
parseTransactionStatus (transaction) {
const canceled = this.safeValue (transaction, 'canceled_at');
if (canceled) {
@@ -817,16 +964,23 @@ module.exports = class coinbasepro extends Exchange {
const updated = this.parse8601 (this.safeString (transaction, 'processed_at'));
const currencyId = this.safeString (transaction, 'currency');
const code = this.safeCurrencyCode (currencyId, currency);
- const fee = undefined;
const status = this.parseTransactionStatus (transaction);
const amount = this.safeFloat (transaction, 'amount');
let type = this.safeString (transaction, 'type');
let address = this.safeString (details, 'crypto_address');
const tag = this.safeString (details, 'destination_tag');
address = this.safeString (transaction, 'crypto_address', address);
+ let fee = undefined;
if (type === 'withdraw') {
type = 'withdrawal';
address = this.safeString (details, 'sent_to_address', address);
+ const feeCost = this.safeFloat (details, 'fee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'code': code,
+ };
+ }
}
return {
'info': transaction,
@@ -869,7 +1023,7 @@ module.exports = class coinbasepro extends Exchange {
const signature = this.hmac (this.encode (what), secret, 'sha256', 'base64');
headers = {
'CB-ACCESS-KEY': this.apiKey,
- 'CB-ACCESS-SIGN': this.decode (signature),
+ 'CB-ACCESS-SIGN': signature,
'CB-ACCESS-TIMESTAMP': nonce,
'CB-ACCESS-PASSPHRASE': this.password,
'Content-Type': 'application/json',
@@ -878,35 +1032,6 @@ module.exports = class coinbasepro extends Exchange {
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
- async fetchDepositAddress (code, params = {}) {
- await this.loadMarkets ();
- const currency = this.currency (code);
- let accounts = this.safeValue (this.options, 'coinbaseAccounts');
- if (accounts === undefined) {
- accounts = await this.privateGetCoinbaseAccounts ();
- this.options['coinbaseAccounts'] = accounts; // cache it
- this.options['coinbaseAccountsByCurrencyId'] = this.indexBy (accounts, 'currency');
- }
- const currencyId = currency['id'];
- const account = this.safeValue (this.options['coinbaseAccountsByCurrencyId'], currencyId);
- if (account === undefined) {
- // eslint-disable-next-line quotes
- throw new InvalidAddress (this.id + " fetchDepositAddress() could not find currency code " + code + " with id = " + currencyId + " in this.options['coinbaseAccountsByCurrencyId']");
- }
- const request = {
- 'id': account['id'],
- };
- const response = await this.privateGetCoinbaseAccountsIdAddresses (this.extend (request, params));
- const address = this.safeString (response, 'address');
- const tag = this.safeString (response, 'destination_tag');
- return {
- 'currency': code,
- 'address': this.checkAddress (address),
- 'tag': tag,
- 'info': response,
- };
- }
-
async createDepositAddress (code, params = {}) {
await this.loadMarkets ();
const currency = this.currency (code);
diff --git a/TaskServer/node_modules/ccxt/js/coincheck.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coincheck.js
similarity index 97%
rename from TaskServer/node_modules/ccxt/js/coincheck.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coincheck.js
index 34f00e870..6b2618ad3 100644
--- a/TaskServer/node_modules/ccxt/js/coincheck.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coincheck.js
@@ -15,12 +15,18 @@ module.exports = class coincheck extends Exchange {
'countries': [ 'JP', 'ID' ],
'rateLimit': 1500,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchMyTrades': true,
+ 'fetchOrderBook': true,
+ 'fetchOpenOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27766464-3b5c3c74-5ed9-11e7-840e-31b32968e1da.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87182088-1d6d6380-c2ec-11ea-9c64-8ab9f9b289f5.jpg',
'api': 'https://coincheck.com/api',
'www': 'https://coincheck.com',
'doc': 'https://coincheck.com/documents/exchange/api',
@@ -178,18 +184,7 @@ module.exports = class coincheck extends Exchange {
}
const status = undefined;
const marketId = this.safeString (order, 'pair');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
return {
'id': id,
'clientOrderId': undefined,
@@ -201,9 +196,11 @@ module.exports = class coincheck extends Exchange {
'filled': filled,
'side': side,
'type': undefined,
+ 'timeInForce': undefined,
'status': status,
'symbol': symbol,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'fee': undefined,
'info': order,
diff --git a/TaskServer/node_modules/ccxt/js/coinegg.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinegg.js
similarity index 97%
rename from TaskServer/node_modules/ccxt/js/coinegg.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinegg.js
index 6bb1fbbdb..0918ef9a0 100644
--- a/TaskServer/node_modules/ccxt/js/coinegg.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinegg.js
@@ -14,11 +14,18 @@ module.exports = class coinegg extends Exchange {
'name': 'CoinEgg',
'countries': [ 'CN', 'UK' ],
'has': {
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': 'emulated',
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchMyTrades': false,
+ 'fetchOpenOrders': 'emulated',
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
'fetchTickers': false,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/36770310-adfa764e-1c5a-11e8-8e09-449daac3d2fb.jpg',
@@ -359,8 +366,10 @@ module.exports = class coinegg extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': undefined,
'amount': amount,
'filled': filled,
@@ -393,7 +402,6 @@ module.exports = class coinegg extends Exchange {
'type': side,
'info': response,
}, market);
- this.orders[id] = order;
return order;
}
@@ -417,7 +425,8 @@ module.exports = class coinegg extends Exchange {
'quote': market['quoteId'],
};
const response = await this.privatePostTradeViewRegionQuote (this.extend (request, params));
- return this.parseOrder (response['data'], market);
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -431,7 +440,8 @@ module.exports = class coinegg extends Exchange {
request['since'] = since / 1000;
}
const response = await this.privatePostTradeListRegionQuote (this.extend (request, params));
- return this.parseOrders (response['data'], market, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOrders (data, market, since, limit);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
diff --git a/TaskServer/node_modules/ccxt/js/coinex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinex.js
similarity index 86%
rename from TaskServer/node_modules/ccxt/js/coinex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinex.js
index 410b3a864..91f4c2052 100644
--- a/TaskServer/node_modules/ccxt/js/coinex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinex.js
@@ -16,15 +16,22 @@ module.exports = class coinex extends Exchange {
'countries': [ 'CN' ],
'rateLimit': 1000,
'has': {
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchMyTrades': true,
- 'withdraw': true,
'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1min',
@@ -42,7 +49,7 @@ module.exports = class coinex extends Exchange {
'1w': '1week',
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/38046312-0b450aac-32c8-11e8-99ab-bc6b136b6cc7.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87182089-1e05fa00-c2ec-11ea-8da9-cc73b45abbbc.jpg',
'api': 'https://api.coinex.com',
'www': 'https://www.coinex.com',
'doc': 'https://github.com/coinexcom/coinex_exchange_api/wiki',
@@ -258,19 +265,16 @@ module.exports = class coinex extends Exchange {
const result = {};
for (let i = 0; i < marketIds.length; i++) {
const marketId = marketIds[i];
- let symbol = marketId;
- let market = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
- const ticker = {
+ const market = this.safeMarket (marketId);
+ const symbol = market['symbol'];
+ const ticker = this.parseTicker ({
'date': timestamp,
'ticker': tickers[marketId],
- };
- result[symbol] = this.parseTicker (ticker, market);
+ }, market);
+ ticker['symbol'] = symbol;
+ result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = 20, params = {}) {
@@ -298,11 +302,7 @@ module.exports = class coinex extends Exchange {
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'amount');
const marketId = this.safeString (trade, 'market');
- market = this.safeValue (this.markets_by_id, marketId, market);
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
let cost = this.safeFloat (trade, 'deal_money');
if (!cost) {
cost = parseFloat (this.costToPrecision (symbol, price * amount));
@@ -346,14 +346,26 @@ module.exports = class coinex extends Exchange {
return this.parseTrades (response['data'], market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591484400,
+ // "0.02505349",
+ // "0.02506988",
+ // "0.02507000",
+ // "0.02505304",
+ // "343.19716223",
+ // "8.6021323866383196",
+ // "ETHBTC"
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[5]),
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -364,8 +376,23 @@ module.exports = class coinex extends Exchange {
'market': market['id'],
'type': this.timeframes[timeframe],
};
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
const response = await this.publicGetMarketKline (this.extend (request, params));
- return this.parseOHLCVs (response['data'], market, timeframe, since, limit);
+ //
+ // {
+ // "code": 0,
+ // "data": [
+ // [1591484400, "0.02505349", "0.02506988", "0.02507000", "0.02505304", "343.19716223", "8.6021323866383196", "ETHBTC"],
+ // [1591484700, "0.02506990", "0.02508109", "0.02508109", "0.02506979", "91.59841581", "2.2972047780447000", "ETHBTC"],
+ // [1591485000, "0.02508106", "0.02507996", "0.02508106", "0.02507500", "65.15307697", "1.6340597822306000", "ETHBTC"],
+ // ],
+ // "message": "OK"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async fetchBalance (params = {}) {
@@ -449,7 +476,7 @@ module.exports = class coinex extends Exchange {
const average = this.safeFloat (order, 'avg_price');
let symbol = undefined;
const marketId = this.safeString (order, 'market');
- market = this.safeValue (this.markets_by_id, marketId);
+ market = this.safeMarket (marketId, market);
const feeCurrencyId = this.safeString (order, 'fee_asset');
let feeCurrency = this.safeCurrencyCode (feeCurrencyId);
if (market !== undefined) {
@@ -471,8 +498,10 @@ module.exports = class coinex extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -515,10 +544,8 @@ module.exports = class coinex extends Exchange {
request['price'] = this.priceToPrecision (symbol, price);
}
const response = await this[method] (this.extend (request, params));
- const order = this.parseOrder (response['data'], market);
- const id = order['id'];
- this.orders[id] = order;
- return order;
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -529,7 +556,8 @@ module.exports = class coinex extends Exchange {
'market': market['id'],
};
const response = await this.privateDeleteOrderPending (this.extend (request, params));
- return this.parseOrder (response['data'], market);
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async fetchOrder (id, symbol = undefined, params = {}) {
@@ -569,7 +597,8 @@ module.exports = class coinex extends Exchange {
// "message": "Ok"
// }
//
- return this.parseOrder (response['data'], market);
+ const data = this.safeValue (response, 'data');
+ return this.parseOrder (data, market);
}
async fetchOrdersByStatus (status, symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -588,7 +617,9 @@ module.exports = class coinex extends Exchange {
}
const method = 'privateGetOrder' + this.capitalize (status);
const response = await this[method] (this.extend (request, params));
- return this.parseOrders (response['data']['data'], market, since, limit);
+ const data = this.safeValue (response, 'data');
+ const orders = this.safeValue (data, 'data', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -614,7 +645,9 @@ module.exports = class coinex extends Exchange {
request['market'] = market['id'];
}
const response = await this.privateGetOrderUserDeals (this.extend (request, params));
- return this.parseTrades (response['data']['data'], market, since, limit);
+ const data = this.safeValue (response, 'data');
+ const trades = this.safeValue (data, 'data', []);
+ return this.parseTrades (trades, market, since, limit);
}
async withdraw (code, amount, address, tag = undefined, params = {}) {
@@ -628,7 +661,7 @@ module.exports = class coinex extends Exchange {
'coin_type': currency['id'],
'coin_address': address, // must be authorized, inter-user transfer by a registered mobile phone number or an email address is supported
'actual_amount': parseFloat (amount), // the actual amount without fees, https://www.coinex.com/fees
- 'transfer_method': '1', // '1' = normal onchain transfer, '2' = internal local transfer from one user to another
+ 'transfer_method': 'onchain', // onchain, local
};
const response = await this.privatePostBalanceCoinWithdraw (this.extend (request, params));
//
@@ -768,48 +801,46 @@ module.exports = class coinex extends Exchange {
//
// {
// "code": 0,
- // "data": [
- // {
- // "actual_amount": "1.00000000",
- // "amount": "1.00000000",
- // "coin_address": "1KAv3pazbTk2JnQ5xTo6fpKK7p1it2RzD4",
- // "coin_type": "BCH",
- // "coin_withdraw_id": 206,
- // "confirmations": 0,
- // "create_time": 1524228297,
- // "status": "audit",
- // "tx_fee": "0",
- // "tx_id": ""
- // },
- // {
- // "actual_amount": "0.10000000",
- // "amount": "0.10000000",
- // "coin_address": "15sr1VdyXQ6sVLqeJUJ1uPzLpmQtgUeBSB",
- // "coin_type": "BCH",
- // "coin_withdraw_id": 203,
- // "confirmations": 11,
- // "create_time": 1515806440,
- // "status": "finish",
- // "tx_fee": "0",
- // "tx_id": "896371d0e23d64d1cac65a0b7c9e9093d835affb572fec89dd4547277fbdd2f6"
- // },
- // {
- // "actual_amount": "0.00100000",
- // "amount": "0.00100000",
- // "coin_address": "1GVVx5UBddLKrckTprNi4VhHSymeQ8tsLF",
- // "coin_type": "BCH",
- // "coin_withdraw_id": 27,
- // "confirmations": 0,
- // "create_time": 1513933541,
- // "status": "cancel",
- // "tx_fee": "0",
- // "tx_id": ""
- // }
- // ],
- // "message": "Ok"
+ // "data": {
+ // "has_next": true,
+ // "curr_page": 1,
+ // "count": 10,
+ // "data": [
+ // {
+ // "coin_withdraw_id": 203,
+ // "create_time": 1513933541,
+ // "actual_amount": "0.00100000",
+ // "actual_amount_display": "***",
+ // "amount": "0.00100000",
+ // "amount_display": "******",
+ // "coin_address": "1GVVx5UBddLKrckTprNi4VhHSymeQ8tsLF",
+ // "app_coin_address_display": "**********",
+ // "coin_address_display": "****************",
+ // "add_explorer": "https://explorer.viawallet.com/btc/address/1GVVx5UBddLKrckTprNi4VhHSymeQ8tsLF",
+ // "coin_type": "BTC",
+ // "confirmations": 6,
+ // "explorer": "https://explorer.viawallet.com/btc/tx/1GVVx5UBddLKrckTprNi4VhHSymeQ8tsLF",
+ // "fee": "0",
+ // "remark": "",
+ // "smart_contract_name": "BTC",
+ // "status": "finish",
+ // "status_display": "finish",
+ // "transfer_method": "onchain",
+ // "tx_fee": "0",
+ // "tx_id": "896371d0e23d64d1cac65a0b7c9e9093d835affb572fec89dd4547277fbdd2f6"
+ // }, /* many more data points */
+ // ],
+ // "total": ***,
+ // "total_page":***
+ // },
+ // "message": "Success"
// }
//
- return this.parseTransactions (response['data'], currency, since, limit);
+ let data = this.safeValue (response, 'data');
+ if (!Array.isArray (data)) {
+ data = this.safeValue (data, 'data', []);
+ }
+ return this.parseTransactions (data, currency, since, limit);
}
async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
@@ -852,7 +883,11 @@ module.exports = class coinex extends Exchange {
// "message": "Ok"
// }
//
- return this.parseTransactions (response['data'], currency, since, limit);
+ let data = this.safeValue (response, 'data');
+ if (!Array.isArray (data)) {
+ data = this.safeValue (data, 'data', []);
+ }
+ return this.parseTransactions (data, currency, since, limit);
}
nonce () {
diff --git a/TaskServer/node_modules/ccxt/js/coinfalcon.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinfalcon.js
similarity index 88%
rename from TaskServer/node_modules/ccxt/js/coinfalcon.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinfalcon.js
index 79a0ab615..563a4c987 100644
--- a/TaskServer/node_modules/ccxt/js/coinfalcon.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinfalcon.js
@@ -16,9 +16,17 @@ module.exports = class coinfalcon extends Exchange {
'rateLimit': 1000,
'version': 'v1',
'has': {
- 'fetchTickers': true,
- 'fetchOpenOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/41822275-ed982188-77f5-11e8-92bb-496bcd14ca52.jpg',
@@ -109,14 +117,8 @@ module.exports = class coinfalcon extends Exchange {
}
parseTicker (ticker, market = undefined) {
- if (market === undefined) {
- const marketId = this.safeString (ticker, 'name');
- market = this.safeValue (this.markets_by_id, marketId, market);
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (ticker, 'name');
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.milliseconds ();
const last = parseFloat (ticker['last_price']);
return {
@@ -159,7 +161,7 @@ module.exports = class coinfalcon extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -169,7 +171,8 @@ module.exports = class coinfalcon extends Exchange {
'level': '3',
};
const response = await this.publicGetMarketsMarketOrders (this.extend (request, params));
- return this.parseOrderBook (response['data'], undefined, 'bids', 'asks', 'price', 'size');
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrderBook (data, undefined, 'bids', 'asks', 'price', 'size');
}
parseTrade (trade, market = undefined) {
@@ -228,7 +231,8 @@ module.exports = class coinfalcon extends Exchange {
request['limit'] = limit;
}
const response = await this.privateGetUserTrades (this.extend (request, params));
- return this.parseTrades (response['data'], market, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
}
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
@@ -241,7 +245,8 @@ module.exports = class coinfalcon extends Exchange {
request['since'] = this.iso8601 (since);
}
const response = await this.publicGetMarketsMarketTrades (this.extend (request, params));
- return this.parseTrades (response['data'], market, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
}
async fetchBalance (params = {}) {
@@ -292,16 +297,8 @@ module.exports = class coinfalcon extends Exchange {
// "created_at":"2018-01-12T21:14:06.747828Z"
// }
//
- if (market === undefined) {
- const marketId = this.safeString (order, 'market');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const price = this.safeFloat (order, 'price');
const amount = this.safeFloat (order, 'size');
@@ -310,10 +307,10 @@ module.exports = class coinfalcon extends Exchange {
let cost = undefined;
if (amount !== undefined) {
if (filled !== undefined) {
- remaining = parseFloat (this.amountToPrecision (symbol, amount - filled));
+ remaining = Math.max (0, amount - filled);
}
if (price !== undefined) {
- cost = parseFloat (this.priceToPrecision (symbol, filled * price));
+ cost = filled * price;
}
}
const status = this.parseOrderStatus (this.safeString (order, 'status'));
@@ -331,8 +328,10 @@ module.exports = class coinfalcon extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -360,10 +359,8 @@ module.exports = class coinfalcon extends Exchange {
}
request['operation_type'] = type + '_order';
const response = await this.privatePostUserOrders (this.extend (request, params));
- const order = this.parseOrder (response['data'], market);
- const id = order['id'];
- this.orders[id] = order;
- return order;
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -373,7 +370,8 @@ module.exports = class coinfalcon extends Exchange {
};
const response = await this.privateDeleteUserOrdersId (this.extend (request, params));
const market = this.market (symbol);
- return this.parseOrder (response['data'], market);
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data, market);
}
async fetchOrder (id, symbol = undefined, params = {}) {
@@ -382,21 +380,26 @@ module.exports = class coinfalcon extends Exchange {
'id': id,
};
const response = await this.privateGetUserOrdersId (this.extend (request, params));
- return this.parseOrder (response['data']);
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
+ let market = undefined;
if (symbol !== undefined) {
- request['market'] = this.marketId (symbol);
+ market = this.market (symbol);
+ request['market'] = market['id'];
}
if (since !== undefined) {
- request['since_time'] = this.iso8601 (this.milliseconds ());
+ request['since_time'] = this.iso8601 (since);
}
// TODO: test status=all if it works for closed orders too
const response = await this.privateGetUserOrders (this.extend (request, params));
- return this.parseOrders (response['data']);
+ const data = this.safeValue (response, 'data', []);
+ const orders = this.filterByArray (data, 'status', [ 'pending', 'open', 'partially_filled' ], false);
+ return this.parseOrders (orders, market, since, limit);
}
nonce () {
diff --git a/TaskServer/node_modules/ccxt/js/coinfloor.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinfloor.js
similarity index 93%
rename from TaskServer/node_modules/ccxt/js/coinfloor.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinfloor.js
index 6ea4f339a..5d59bdf98 100644
--- a/TaskServer/node_modules/ccxt/js/coinfloor.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinfloor.js
@@ -15,11 +15,18 @@ module.exports = class coinfloor extends Exchange {
'rateLimit': 1000,
'countries': [ 'UK' ],
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchLedger': true,
'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/28246081-623fc164-6a1c-11e7-913f-bac0d5576c90.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87153925-ef265e80-c2c0-11ea-91b5-020c804b90e0.jpg',
'api': 'https://webapi.coinfloor.co.uk/bist',
'www': 'https://www.coinfloor.co.uk',
'doc': [
@@ -399,7 +406,27 @@ module.exports = class coinfloor extends Exchange {
request['price'] = price;
request['amount'] = amount;
}
- return await this[method] (this.extend (request, params));
+ //
+ // {
+ // "id":31950584,
+ // "datetime":"2020-05-21 08:38:18",
+ // "type":1,
+ // "price":"9100",
+ // "amount":"0.0026"
+ // }
+ //
+ const response = await this[method] (this.extend (request, params));
+ const timestamp = this.parse8601 (this.safeString (response, 'datetime'));
+ return {
+ 'id': this.safeString (response, 'id'),
+ 'clientOrderId': undefined,
+ 'datetime': this.iso8601 (timestamp),
+ 'timestamp': timestamp,
+ 'type': type,
+ 'price': this.safeFloat (response, 'price'),
+ 'remaining': this.safeFloat (response, 'amount'),
+ 'info': response,
+ };
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -452,11 +479,13 @@ module.exports = class coinfloor extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
- 'amount': amount,
+ 'stopPrice': undefined,
+ 'amount': undefined,
'filled': undefined,
- 'remaining': undefined,
+ 'remaining': amount,
'cost': cost,
'fee': undefined,
'average': undefined,
@@ -510,7 +539,7 @@ module.exports = class coinfloor extends Exchange {
const nonce = this.nonce ();
body = this.urlencode (this.extend ({ 'nonce': nonce }, query));
const auth = this.uid + '/' + this.apiKey + ':' + this.password;
- const signature = this.decode (this.stringToBase64 (this.encode (auth)));
+ const signature = this.decode (this.stringToBase64 (auth));
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Basic ' + signature,
diff --git a/TaskServer/node_modules/ccxt/js/coingi.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coingi.js
similarity index 97%
rename from TaskServer/node_modules/ccxt/js/coingi.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coingi.js
index 03197be93..650d80885 100644
--- a/TaskServer/node_modules/ccxt/js/coingi.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coingi.js
@@ -15,8 +15,15 @@ module.exports = class coingi extends Exchange {
'rateLimit': 1000,
'countries': [ 'PA', 'BG', 'CN', 'US' ], // Panama, Bulgaria, China, US
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'referral': 'https://www.coingi.com/?r=XTPPMC',
@@ -226,7 +233,7 @@ module.exports = class coingi extends Exchange {
}
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -250,13 +257,7 @@ module.exports = class coingi extends Exchange {
const timestamp = this.safeInteger (trade, 'timestamp');
const id = this.safeString (trade, 'id');
const marketId = this.safeString (trade, 'currencyPair');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
return {
'id': id,
'info': trade,
diff --git a/TaskServer/node_modules/ccxt/js/coinmarketcap.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinmarketcap.js
similarity index 93%
rename from TaskServer/node_modules/ccxt/js/coinmarketcap.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinmarketcap.js
index b9338c4c7..3d983cc88 100644
--- a/TaskServer/node_modules/ccxt/js/coinmarketcap.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinmarketcap.js
@@ -16,23 +16,25 @@ module.exports = class coinmarketcap extends Exchange {
'version': 'v1',
'countries': [ 'US' ],
'has': {
- 'CORS': true,
- 'privateAPI': false,
- 'createOrder': false,
- 'createMarketOrder': false,
- 'createLimitOrder': false,
'cancelOrder': false,
+ 'CORS': true,
+ 'createLimitOrder': false,
+ 'createMarketOrder': false,
+ 'createOrder': false,
'editOrder': false,
+ 'privateAPI': false,
'fetchBalance': false,
- 'fetchOrderBook': false,
- 'fetchL2OrderBook': false,
- 'fetchOHLCV': false,
- 'fetchTrades': false,
- 'fetchTickers': true,
'fetchCurrencies': true,
+ 'fetchL2OrderBook': false,
+ 'fetchMarkets': true,
+ 'fetchOHLCV': false,
+ 'fetchOrderBook': false,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': false,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/28244244-9be6312a-69ed-11e7-99c1-7c1797275265.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87182086-1cd4cd00-c2ec-11ea-9ec4-d0cf2a2abf62.jpg',
'api': {
'public': 'https://api.coinmarketcap.com',
'files': 'https://files.coinmarketcap.com',
@@ -96,24 +98,29 @@ module.exports = class coinmarketcap extends Exchange {
'ACChain': 'ACChain',
'AdCoin': 'AdCoin',
'BatCoin': 'BatCoin',
+ 'BigONE Token': 'BigONE Token', // conflict with Harmony (ONE)
'Bitgem': 'Bitgem',
'BlazeCoin': 'BlazeCoin',
'BlockCAT': 'BlockCAT',
'Blocktrade Token': 'Blocktrade Token',
+ 'BOX Token': 'BOX Token', // conflict with BOX (ContentBox)
'Catcoin': 'Catcoin',
'CanYaCoin': 'CanYaCoin', // conflict with CAN (Content and AD Network)
+ 'CryptoBossCoin': 'CryptoBossCoin', // conflict with CBC (CashBet Coin)
'Comet': 'Comet', // conflict with CMT (CyberMiles)
'CPChain': 'CPChain',
'CrowdCoin': 'CrowdCoin', // conflict with CRC CryCash
'Cryptaur': 'Cryptaur', // conflict with CPT = Contents Protocol https://github.com/ccxt/ccxt/issues/4920 and https://github.com/ccxt/ccxt/issues/6081
'Cubits': 'Cubits', // conflict with QBT (Qbao)
'DAO.Casino': 'DAO.Casino', // conflict with BET (BetaCoin)
+ 'DefiBox': 'DefiBox', // conflict with BOX (ContentBox)
'E-Dinar Coin': 'E-Dinar Coin', // conflict with EDR Endor Protocol and EDRCoin
'EDRcoin': 'EDRcoin', // conflict with EDR Endor Protocol and E-Dinar Coin
'ENTCash': 'ENTCash', // conflict with ENT (Eternity)
'FairCoin': 'FairCoin', // conflict with FAIR (FairGame) https://github.com/ccxt/ccxt/pull/5865
'Fabric Token': 'Fabric Token',
// 'GET Protocol': 'GET Protocol',
+ 'GHOSTPRISM': 'GHOSTPRISM', // conflict with GHOST
'Global Tour Coin': 'Global Tour Coin', // conflict with GTC (Game.com)
'GuccioneCoin': 'GuccioneCoin', // conflict with GCC (Global Cryptocurrency)
'HarmonyCoin': 'HarmonyCoin', // conflict with HMC (Hi Mutual Society)
@@ -123,14 +130,18 @@ module.exports = class coinmarketcap extends Exchange {
'Huncoin': 'Huncoin', // conflict with HNC (Helleniccoin)
'iCoin': 'iCoin',
'Infinity Economics': 'Infinity Economics', // conflict with XIN (Mixin)
+ 'IQ.cash': 'IQ.cash', // conflict with IQ (Everipedia)
'KingN Coin': 'KingN Coin', // conflict with KNC (Kyber Network)
'LiteBitcoin': 'LiteBitcoin', // conflict with LBTC (LightningBitcoin)
'Maggie': 'Maggie',
+ 'Menlo One': 'Menlo One', // conflict with Harmony (ONE)
+ 'Mobilian Coin': 'Mobilian Coin', // conflict with Membrana (MBN)
'Monarch': 'Monarch', // conflict with MyToken (MT)
'MTC Mesh Network': 'MTC Mesh Network', // conflict with MTC Docademic doc.com Token https://github.com/ccxt/ccxt/issues/6081 https://github.com/ccxt/ccxt/issues/3025
'IOTA': 'IOTA', // a special case, most exchanges list it as IOTA, therefore we change just the Coinmarketcap instead of changing them all
'NetCoin': 'NetCoin',
'PCHAIN': 'PCHAIN', // conflict with PAI (Project Pai)
+ 'Penta': 'Penta', // conflict with PNT (pNetwork)
'Plair': 'Plair', // conflict with PLA (PLANET)
'PlayChip': 'PlayChip', // conflict with PLA (PLANET)
'Polcoin': 'Polcoin',
@@ -139,9 +150,11 @@ module.exports = class coinmarketcap extends Exchange {
// https://github.com/ccxt/ccxt/issues/6081
// https://github.com/ccxt/ccxt/issues/3365
// https://github.com/ccxt/ccxt/issues/2873
+ 'TerraCredit': 'TerraCredit', // conflict with CREDIT (PROXI)
'Themis': 'Themis', // conflict with GET (Guaranteed Entrance Token, GET Protocol)
- 'Menlo One': 'Menlo One', // conflict with Harmony (ONE)
- 'BigONE Token': 'BigONE Token', // conflict with Harmony (ONE)
+ 'UNI COIN': 'UNI COIN', // conflict with UNI (Uniswap)
+ 'UNICORN Token': 'UNICORN Token', // conflict with UNI (Uniswap)
+ 'Universe': 'Universe', // conflict with UNI (Uniswap)
};
return this.safeValue (currencies, name, base);
}
diff --git a/TaskServer/node_modules/ccxt/js/coinmate.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinmate.js
similarity index 94%
rename from TaskServer/node_modules/ccxt/js/coinmate.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinmate.js
index 6e5196f01..844bc0011 100644
--- a/TaskServer/node_modules/ccxt/js/coinmate.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinmate.js
@@ -15,18 +15,22 @@ module.exports = class coinmate extends Exchange {
'countries': [ 'GB', 'CZ', 'EU' ], // UK, Czech Republic
'rateLimit': 1000,
'has': {
- 'CORS': true,
- 'fetchBalance': true,
- 'fetchOrders': true,
- 'fetchOrder': true,
- 'fetchMyTrades': true,
- 'fetchTransactions': true,
- 'fetchOpenOrders': true,
- 'createOrder': true,
'cancelOrder': true,
+ 'CORS': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27811229-c1efb510-606c-11e7-9a36-84ba2ce412d8.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87460806-1c9f3f00-c616-11ea-8c46-a77018a8f3f4.jpg',
'api': 'https://coinmate.io/api',
'www': 'https://coinmate.io',
'fees': 'https://coinmate.io/fees',
@@ -393,7 +397,7 @@ module.exports = class coinmate extends Exchange {
'status': status,
'fee': {
'cost': fee,
- 'currency': currency,
+ 'currency': code,
},
'info': item,
};
@@ -447,25 +451,8 @@ module.exports = class coinmate extends Exchange {
// "tradeType":"BUY"
// }
//
- let symbol = undefined;
const marketId = this.safeString (trade, 'currencyPair');
- let quote = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id[marketId]) {
- market = this.markets_by_id[marketId];
- quote = market['quote'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ market = this.safeMarket (marketId, market, '_');
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'amount');
let cost = undefined;
@@ -484,7 +471,7 @@ module.exports = class coinmate extends Exchange {
if (feeCost !== undefined) {
fee = {
'cost': feeCost,
- 'currency': quote,
+ 'currency': market['quote'],
};
}
let takerOrMaker = this.safeString (trade, 'feeType');
@@ -494,7 +481,7 @@ module.exports = class coinmate extends Exchange {
'info': trade,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': type,
'side': side,
'order': orderId,
@@ -622,14 +609,17 @@ module.exports = class coinmate extends Exchange {
const timestamp = this.safeInteger (order, 'timestamp');
const side = this.safeStringLower (order, 'type');
const price = this.safeFloat (order, 'price');
- const amount = this.safeFloat2 (order, 'originalAmount', 'amount');
- const remaining = this.safeFloat (order, 'remainingAmount', amount);
+ const amount = this.safeFloat (order, 'originalAmount');
+ let remaining = this.safeFloat (order, 'remainingAmount');
+ if (remaining === undefined) {
+ remaining = this.safeFloat (order, 'amount');
+ }
let status = this.parseOrderStatus (this.safeString (order, 'status'));
const type = this.parseOrderType (this.safeString (order, 'orderTradeType'));
let filled = undefined;
let cost = undefined;
if ((amount !== undefined) && (remaining !== undefined)) {
- filled = Math.min (amount - remaining, 0);
+ filled = Math.max (amount - remaining, 0);
if (remaining === 0) {
status = 'closed';
}
@@ -638,22 +628,10 @@ module.exports = class coinmate extends Exchange {
}
}
const average = this.safeFloat (order, 'avgPrice');
- let symbol = undefined;
const marketId = this.safeString (order, 'currencyPair');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const clientOrderId = this.safeString (order, 'clientOrderId');
+ const stopPrice = this.safeFloat (order, 'stopPrice');
return {
'id': id,
'clientOrderId': clientOrderId,
@@ -662,8 +640,10 @@ module.exports = class coinmate extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinone.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinone.js
new file mode 100644
index 000000000..eb14695fa
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinone.js
@@ -0,0 +1,681 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { BadSymbol, BadRequest, ExchangeError, ArgumentsRequired, OrderNotFound, OnMaintenance } = require ('./base/errors');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class coinone extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'coinone',
+ 'name': 'CoinOne',
+ 'countries': [ 'KR' ], // Korea
+ // 'enableRateLimit': false,
+ 'rateLimit': 667,
+ 'version': 'v2',
+ 'has': {
+ 'cancelOrder': true,
+ 'CORS': false,
+ 'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': false,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ // https://github.com/ccxt/ccxt/pull/7067
+ // the endpoint that should return closed orders actually returns trades
+ 'fetchClosedOrders': false,
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/38003300-adc12fba-323f-11e8-8525-725f53c4a659.jpg',
+ 'api': 'https://api.coinone.co.kr',
+ 'www': 'https://coinone.co.kr',
+ 'doc': 'https://doc.coinone.co.kr',
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'orderbook/',
+ 'trades/',
+ 'ticker/',
+ ],
+ },
+ 'private': {
+ 'post': [
+ 'account/btc_deposit_address/',
+ 'account/balance/',
+ 'account/daily_balance/',
+ 'account/user_info/',
+ 'account/virtual_account/',
+ 'order/cancel_all/',
+ 'order/cancel/',
+ 'order/limit_buy/',
+ 'order/limit_sell/',
+ 'order/complete_orders/',
+ 'order/limit_orders/',
+ 'order/order_info/',
+ 'transaction/auth_number/',
+ 'transaction/history/',
+ 'transaction/krw/history/',
+ 'transaction/btc/',
+ 'transaction/coin/',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': false,
+ 'percentage': true,
+ 'taker': 0.002,
+ 'maker': 0.002,
+ },
+ },
+ 'precision': {
+ 'price': 4,
+ 'amount': 4,
+ 'cost': 8,
+ },
+ 'exceptions': {
+ '405': OnMaintenance, // {"errorCode":"405","status":"maintenance","result":"error"}
+ '104': OrderNotFound, // {"errorCode":"104","errorMsg":"Order id is not exist","result":"error"}
+ '108': BadSymbol, // {"errorCode":"108","errorMsg":"Unknown CryptoCurrency","result":"error"}
+ '107': BadRequest, // {"errorCode":"107","errorMsg":"Parameter error","result":"error"}
+ },
+ });
+ }
+
+ async fetchMarkets (params = {}) {
+ const request = {
+ 'currency': 'all',
+ };
+ const response = await this.publicGetTicker (request);
+ const result = [];
+ const quoteId = 'krw';
+ const quote = this.safeCurrencyCode (quoteId);
+ const baseIds = Object.keys (response);
+ for (let i = 0; i < baseIds.length; i++) {
+ const baseId = baseIds[i];
+ const ticker = this.safeValue (response, baseId, {});
+ const currency = this.safeValue (ticker, 'currency');
+ if (currency === undefined) {
+ continue;
+ }
+ const base = this.safeCurrencyCode (baseId);
+ result.push ({
+ 'id': baseId,
+ 'symbol': base + '/' + quote,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'active': true,
+ });
+ }
+ return result;
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privatePostAccountBalance (params);
+ const result = { 'info': response };
+ const balances = this.omit (response, [
+ 'errorCode',
+ 'result',
+ 'normalWallets',
+ ]);
+ const currencyIds = Object.keys (balances);
+ for (let i = 0; i < currencyIds.length; i++) {
+ const currencyId = currencyIds[i];
+ const balance = balances[currencyId];
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['free'] = this.safeFloat (balance, 'avail');
+ account['total'] = this.safeFloat (balance, 'balance');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'currency': market['id'],
+ 'format': 'json',
+ };
+ const response = await this.publicGetOrderbook (this.extend (request, params));
+ const timestamp = this.safeTimestamp (response, 'timestamp');
+ return this.parseOrderBook (response, timestamp, 'bid', 'ask', 'price', 'qty');
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'currency': 'all',
+ 'format': 'json',
+ };
+ const response = await this.publicGetTicker (this.extend (request, params));
+ const result = {};
+ const ids = Object.keys (response);
+ const timestamp = this.safeTimestamp (response, 'timestamp');
+ for (let i = 0; i < ids.length; i++) {
+ const id = ids[i];
+ let symbol = id;
+ let market = undefined;
+ if (id in this.markets_by_id) {
+ market = this.markets_by_id[id];
+ symbol = market['symbol'];
+ const ticker = response[id];
+ result[symbol] = this.parseTicker (ticker, market);
+ result[symbol]['timestamp'] = timestamp;
+ }
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'currency': market['id'],
+ 'format': 'json',
+ };
+ const response = await this.publicGetTicker (this.extend (request, params));
+ return this.parseTicker (response, market);
+ }
+
+ parseTicker (ticker, market = undefined) {
+ const timestamp = this.safeTimestamp (ticker, 'timestamp');
+ const first = this.safeFloat (ticker, 'first');
+ const last = this.safeFloat (ticker, 'last');
+ let average = undefined;
+ if (first !== undefined && last !== undefined) {
+ average = this.sum (first, last) / 2;
+ }
+ const previousClose = this.safeFloat (ticker, 'yesterday_last');
+ let change = undefined;
+ let percentage = undefined;
+ if (last !== undefined && previousClose !== undefined) {
+ change = last - previousClose;
+ if (previousClose !== 0) {
+ percentage = change / previousClose * 100;
+ }
+ }
+ const symbol = (market !== undefined) ? market['symbol'] : undefined;
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': undefined,
+ 'bidVolume': undefined,
+ 'ask': undefined,
+ 'askVolume': undefined,
+ 'vwap': undefined,
+ 'open': first,
+ 'close': last,
+ 'last': last,
+ 'previousClose': previousClose,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': this.safeFloat (ticker, 'volume'),
+ 'quoteVolume': undefined,
+ 'info': ticker,
+ };
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // fetchTrades (public)
+ //
+ // {
+ // "timestamp": "1416893212",
+ // "price": "420000.0",
+ // "qty": "0.1",
+ // "is_ask": "1"
+ // }
+ //
+ // fetchMyTrades (private)
+ //
+ // {
+ // "timestamp": "1416561032",
+ // "price": "419000.0",
+ // "type": "bid",
+ // "qty": "0.001",
+ // "feeRate": "-0.0015",
+ // "fee": "-0.0000015",
+ // "orderId": "E84A1AC2-8088-4FA0-B093-A3BCDB9B3C85"
+ // }
+ //
+ const timestamp = this.safeTimestamp (trade, 'timestamp');
+ const symbol = (market !== undefined) ? market['symbol'] : undefined;
+ const is_ask = this.safeString (trade, 'is_ask');
+ let side = this.safeString (trade, 'type');
+ if (is_ask !== undefined) {
+ if (is_ask === '1') {
+ side = 'sell';
+ } else if (is_ask === '0') {
+ side = 'buy';
+ }
+ } else {
+ if (side === 'ask') {
+ side = 'sell';
+ } else if (side === 'bid') {
+ side = 'buy';
+ }
+ }
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'qty');
+ let cost = undefined;
+ if (price !== undefined) {
+ if (amount !== undefined) {
+ cost = price * amount;
+ }
+ }
+ const orderId = this.safeString (trade, 'orderId');
+ let feeCost = this.safeFloat (trade, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ feeCost = Math.abs (feeCost);
+ let feeRate = this.safeFloat (trade, 'feeRate');
+ feeRate = Math.abs (feeRate);
+ let feeCurrencyCode = undefined;
+ if (market !== undefined) {
+ feeCurrencyCode = (side === 'sell') ? market['quote'] : market['base'];
+ }
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ 'rate': feeRate,
+ };
+ }
+ return {
+ 'id': this.safeString (trade, 'id'),
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'order': orderId,
+ 'symbol': symbol,
+ 'type': undefined,
+ 'side': side,
+ 'takerOrMaker': undefined,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'currency': market['id'],
+ 'format': 'json',
+ };
+ const response = await this.publicGetTrades (this.extend (request, params));
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "timestamp": "1416895635",
+ // "currency": "btc",
+ // "completeOrders": [
+ // {
+ // "timestamp": "1416893212",
+ // "price": "420000.0",
+ // "qty": "0.1",
+ // "is_ask": "1"
+ // }
+ // ]
+ // }
+ //
+ const completeOrders = this.safeValue (response, 'completeOrders', []);
+ return this.parseTrades (completeOrders, market, since, limit);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ if (type !== 'limit') {
+ throw new ExchangeError (this.id + ' allows limit orders only');
+ }
+ await this.loadMarkets ();
+ const request = {
+ 'price': price,
+ 'currency': this.marketId (symbol),
+ 'qty': amount,
+ };
+ const method = 'privatePostOrder' + this.capitalize (type) + this.capitalize (side);
+ const response = await this[method] (this.extend (request, params));
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "orderId": "8a82c561-40b4-4cb3-9bc0-9ac9ffc1d63b"
+ // }
+ //
+ return this.parseOrder (response);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'order_id': id,
+ 'currency': market['id'],
+ };
+ const response = await this.privatePostOrderOrderInfo (this.extend (request, params));
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "status": "live",
+ // "info": {
+ // "orderId": "32FF744B-D501-423A-8BA1-05BB6BE7814A",
+ // "currency": "BTC",
+ // "type": "bid",
+ // "price": "2922000.0",
+ // "qty": "115.4950",
+ // "remainQty": "45.4950",
+ // "feeRate": "0.0003",
+ // "fee": "0",
+ // "timestamp": "1499340941"
+ // }
+ // }
+ //
+ const info = this.safeValue (response, 'info', {});
+ info['status'] = this.safeString (info, 'status');
+ return this.parseOrder (info, market);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'live': 'open',
+ 'partially_filled': 'open',
+ 'filled': 'closed',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "orderId": "8a82c561-40b4-4cb3-9bc0-9ac9ffc1d63b"
+ // }
+ //
+ // fetchOrder
+ //
+ // {
+ // "status": "live", // injected in fetchOrder
+ // "orderId": "32FF744B-D501-423A-8BA1-05BB6BE7814A",
+ // "currency": "BTC",
+ // "type": "bid",
+ // "price": "2922000.0",
+ // "qty": "115.4950",
+ // "remainQty": "45.4950",
+ // "feeRate": "0.0003",
+ // "fee": "0",
+ // "timestamp": "1499340941"
+ // }
+ //
+ // fetchOpenOrders
+ //
+ // {
+ // "index": "0",
+ // "orderId": "68665943-1eb5-4e4b-9d76-845fc54f5489",
+ // "timestamp": "1449037367",
+ // "price": "444000.0",
+ // "qty": "0.3456",
+ // "type": "ask",
+ // "feeRate": "-0.0015"
+ // }
+ //
+ const id = this.safeString (order, 'orderId');
+ const price = this.safeFloat (order, 'price');
+ const timestamp = this.safeTimestamp (order, 'timestamp');
+ let side = this.safeString (order, 'type');
+ if (side === 'ask') {
+ side = 'sell';
+ } else if (side === 'bid') {
+ side = 'buy';
+ }
+ const remaining = this.safeFloat (order, 'remainQty');
+ let filled = undefined;
+ const amount = this.safeFloat (order, 'qty');
+ let status = this.safeString (order, 'status');
+ // https://github.com/ccxt/ccxt/pull/7067
+ if (status === 'live') {
+ if ((remaining !== undefined) && (amount !== undefined)) {
+ if (remaining < amount) {
+ status = 'canceled';
+ }
+ }
+ }
+ if ((remaining !== undefined) && (amount !== undefined)) {
+ filled = Math.max (amount - remaining);
+ }
+ status = this.parseOrderStatus (status);
+ let cost = undefined;
+ if ((price !== undefined) && (filled !== undefined)) {
+ cost = price * filled;
+ }
+ let symbol = undefined;
+ let base = undefined;
+ let quote = undefined;
+ const marketId = this.safeStringLower (order, 'currency');
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ base = this.safeCurrencyCode (marketId);
+ quote = 'KRW';
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ base = market['base'];
+ quote = market['quote'];
+ }
+ let fee = undefined;
+ const feeCost = this.safeFloat (order, 'fee');
+ if (feeCost !== undefined) {
+ const feeCurrencyCode = (side === 'sell') ? quote : base;
+ fee = {
+ 'cost': feeCost,
+ 'rate': this.safeFloat (order, 'feeRate'),
+ 'currency': feeCurrencyCode,
+ };
+ }
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': 'limit',
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'cost': cost,
+ 'average': undefined,
+ 'amount': amount,
+ 'filled': filled,
+ 'remaining': amount,
+ 'status': status,
+ 'fee': fee,
+ 'trades': undefined,
+ };
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ // The returned amount might not be same as the ordered amount. If an order is partially filled, the returned amount means the remaining amount.
+ // For the same reason, the returned amount and remaining are always same, and the returned filled and cost are always zero.
+ if (symbol === undefined) {
+ throw new ExchangeError (this.id + ' allows fetching closed orders with a specific symbol');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'currency': market['id'],
+ };
+ const response = await this.privatePostOrderLimitOrders (this.extend (request, params));
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "limitOrders": [
+ // {
+ // "index": "0",
+ // "orderId": "68665943-1eb5-4e4b-9d76-845fc54f5489",
+ // "timestamp": "1449037367",
+ // "price": "444000.0",
+ // "qty": "0.3456",
+ // "type": "ask",
+ // "feeRate": "-0.0015"
+ // }
+ // ]
+ // }
+ //
+ const limitOrders = this.safeValue (response, 'limitOrders', []);
+ return this.parseOrders (limitOrders, market, since, limit);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'currency': market['id'],
+ };
+ const response = await this.privatePostOrderCompleteOrders (this.extend (request, params));
+ //
+ // despite the name of the endpoint it returns trades which may have a duplicate orderId
+ // https://github.com/ccxt/ccxt/pull/7067
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0",
+ // "completeOrders": [
+ // {
+ // "timestamp": "1416561032",
+ // "price": "419000.0",
+ // "type": "bid",
+ // "qty": "0.001",
+ // "feeRate": "-0.0015",
+ // "fee": "-0.0000015",
+ // "orderId": "E84A1AC2-8088-4FA0-B093-A3BCDB9B3C85"
+ // }
+ // ]
+ // }
+ //
+ const completeOrders = this.safeValue (response, 'completeOrders', []);
+ return this.parseTrades (completeOrders, market, since, limit);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ // eslint-disable-next-line quotes
+ throw new ArgumentsRequired (this.id + " cancelOrder requires a symbol argument. To cancel the order, pass a symbol argument and {'price': 12345, 'qty': 1.2345, 'is_ask': 0} in the params argument of cancelOrder.");
+ }
+ const price = this.safeFloat (params, 'price');
+ const qty = this.safeFloat (params, 'qty');
+ const isAsk = this.safeInteger (params, 'is_ask');
+ if ((price === undefined) || (qty === undefined) || (isAsk === undefined)) {
+ // eslint-disable-next-line quotes
+ throw new ArgumentsRequired (this.id + " cancelOrder requires {'price': 12345, 'qty': 1.2345, 'is_ask': 0} in the params argument.");
+ }
+ await this.loadMarkets ();
+ const request = {
+ 'order_id': id,
+ 'price': price,
+ 'qty': qty,
+ 'is_ask': isAsk,
+ 'currency': this.marketId (symbol),
+ };
+ const response = await this.privatePostOrderCancel (this.extend (request, params));
+ //
+ // {
+ // "result": "success",
+ // "errorCode": "0"
+ // }
+ //
+ return response;
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const request = this.implodeParams (path, params);
+ const query = this.omit (params, this.extractParams (path));
+ let url = this.urls['api'] + '/';
+ if (api === 'public') {
+ url += request;
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else {
+ this.checkRequiredCredentials ();
+ url += this.version + '/' + request;
+ const nonce = this.nonce ().toString ();
+ const json = this.json (this.extend ({
+ 'access_token': this.apiKey,
+ 'nonce': nonce,
+ }, params));
+ const payload = this.stringToBase64 (json);
+ body = this.decode (payload);
+ const secret = this.secret.toUpperCase ();
+ const signature = this.hmac (payload, this.encode (secret), 'sha512');
+ headers = {
+ 'Content-Type': 'application/json',
+ 'X-COINONE-PAYLOAD': payload,
+ 'X-COINONE-SIGNATURE': signature,
+ };
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return;
+ }
+ if ('result' in response) {
+ const result = response['result'];
+ if (result !== 'success') {
+ //
+ // { "errorCode": "405", "status": "maintenance", "result": "error"}
+ //
+ const errorCode = this.safeString (response, 'errorCode');
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions, errorCode, feedback);
+ throw new ExchangeError (feedback);
+ }
+ } else {
+ throw new ExchangeError (this.id + ' ' + body);
+ }
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/coinspot.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinspot.js
similarity index 73%
rename from TaskServer/node_modules/ccxt/js/coinspot.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinspot.js
index 2055e5937..2da1a5ee7 100644
--- a/TaskServer/node_modules/ccxt/js/coinspot.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/coinspot.js
@@ -15,8 +15,14 @@ module.exports = class coinspot extends Exchange {
'countries': [ 'AU' ], // Australia
'rateLimit': 1000,
'has': {
+ 'cancelOrder': false,
'CORS': false,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/28208429-3cacdf9a-6896-11e7-854e-4c79a772a30f.jpg',
@@ -48,6 +54,17 @@ module.exports = class coinspot extends Exchange {
'my/sell',
'my/buy/cancel',
'my/sell/cancel',
+ 'ro/my/balances',
+ 'ro/my/balances/{cointype}',
+ 'ro/my/deposits',
+ 'ro/my/withdrawals',
+ 'ro/my/transactions',
+ 'ro/my/transactions/{cointype}',
+ 'ro/my/transactions/open',
+ 'ro/my/transactions/{cointype}/open',
+ 'ro/my/sendreceive',
+ 'ro/my/affiliatepayments',
+ 'ro/my/referralpayments',
],
},
},
@@ -127,10 +144,57 @@ module.exports = class coinspot extends Exchange {
'cointype': market['id'],
};
const response = await this.privatePostOrdersHistory (this.extend (request, params));
+ //
+ // {
+ // "status":"ok",
+ // "orders":[
+ // {"amount":0.00102091,"rate":21549.09999991,"total":21.99969168,"coin":"BTC","solddate":1604890646143,"market":"BTC/AUD"},
+ // ],
+ // }
+ //
const trades = this.safeValue (response, 'orders', []);
return this.parseTrades (trades, market, since, limit);
}
+ parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades
+ //
+ // {
+ // "amount":0.00102091,
+ // "rate":21549.09999991,
+ // "total":21.99969168,
+ // "coin":"BTC",
+ // "solddate":1604890646143,
+ // "market":"BTC/AUD"
+ // }
+ //
+ const price = this.safeFloat (trade, 'rate');
+ const amount = this.safeFloat (trade, 'amount');
+ let cost = this.safeFloat (trade, 'total');
+ if ((cost === undefined) && (price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ const timestamp = this.safeInteger (trade, 'solddate');
+ const marketId = this.safeString (trade, 'market');
+ const symbol = this.safeSymbol (marketId, market, '/');
+ return {
+ 'info': trade,
+ 'id': undefined,
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'order': undefined,
+ 'type': undefined,
+ 'side': undefined,
+ 'takerOrMaker': undefined,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': undefined,
+ };
+ }
+
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const method = 'privatePostMy' + this.capitalize (side);
diff --git a/TaskServer/node_modules/ccxt/js/crex24.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/crex24.js
similarity index 96%
rename from TaskServer/node_modules/ccxt/js/crex24.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/crex24.js
index c99799c7e..5ea3e826c 100644
--- a/TaskServer/node_modules/ccxt/js/crex24.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/crex24.js
@@ -18,21 +18,28 @@ module.exports = class crex24 extends Exchange {
// new metainfo interface
'has': {
'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
'editOrder': true,
+ 'fetchBalance': true,
'fetchBidsAsks': true,
'fetchClosedOrders': true,
'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
'fetchFundingFees': false,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
'fetchOrders': true,
'fetchOrderTrades': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTradingFee': false, // actually, true, but will be implemented later
'fetchTradingFees': false, // actually, true, but will be implemented later
'fetchTransactions': true,
@@ -119,9 +126,15 @@ module.exports = class crex24 extends Exchange {
},
},
'commonCurrencies': {
- 'YOYO': 'YOYOW',
- 'BULL': 'BuySell',
'BCC': 'BCH',
+ 'BIT': 'BitMoney',
+ 'BULL': 'BuySell',
+ 'CREDIT': 'TerraCredit',
+ 'GHOST': 'GHOSTPRISM',
+ 'IQ': 'IQ.Cash',
+ 'PUT': 'PutinCoin',
+ 'UNI': 'Universe',
+ 'YOYO': 'YOYOW',
},
// exchange-specific options
'options': {
@@ -148,6 +161,7 @@ module.exports = class crex24 extends Exchange {
'API Key': AuthenticationError, // "API Key '9edc48de-d5b0-4248-8e7e-f59ffcd1c7f1' doesn't exist."
'Insufficient funds': InsufficientFunds, // "Insufficient funds: new order requires 10 ETH which is more than the available balance."
'has been delisted.': BadSymbol, // {"errorDescription":"Instrument '$PAC-BTC' has been delisted."}
+ 'Mandatory parameter': BadRequest, // {"errorDescription":"Mandatory parameter 'feeCurrency' is missing."}
},
},
});
@@ -375,17 +389,8 @@ module.exports = class crex24 extends Exchange {
// timestamp: "2018-10-31T09:21:25Z" } ]
//
const timestamp = this.parse8601 (this.safeString (ticker, 'timestamp'));
- let symbol = undefined;
const marketId = this.safeString (ticker, 'instrument');
- market = this.safeValue (this.markets_by_id, marketId, market);
- if (market !== undefined) {
- symbol = market['symbol'];
- } else if (marketId !== undefined) {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const last = this.safeFloat (ticker, 'last');
return {
'symbol': symbol,
@@ -519,12 +524,8 @@ module.exports = class crex24 extends Exchange {
const id = this.safeString (trade, 'id');
const side = this.safeString (trade, 'side');
const orderId = this.safeString (trade, 'orderId');
- let symbol = undefined;
const marketId = this.safeString (trade, 'instrument');
- market = this.safeValue (this.markets_by_id, marketId, market);
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
let fee = undefined;
const feeCurrencyId = this.safeString (trade, 'feeCurrency');
const feeCode = this.safeCurrencyCode (feeCurrencyId);
@@ -576,17 +577,19 @@ module.exports = class crex24 extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
- // { timestamp: '2019-09-21T10:36:00Z',
- // open: 0.02152,
- // high: 0.02156,
- // low: 0.02152,
- // close: 0.02156,
- // volume: 0.01741259 }
- const date = this.safeString (ohlcv, 'timestamp');
- const timestamp = this.parse8601 (date);
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // timestamp: '2019-09-21T10:36:00Z',
+ // open: 0.02152,
+ // high: 0.02156,
+ // low: 0.02152,
+ // close: 0.02156,
+ // volume: 0.01741259
+ // }
+ //
return [
- timestamp,
+ this.parse8601 (this.safeString (ohlcv, 'timestamp')),
this.safeFloat (ohlcv, 'open'),
this.safeFloat (ohlcv, 'high'),
this.safeFloat (ohlcv, 'low'),
@@ -606,6 +609,18 @@ module.exports = class crex24 extends Exchange {
request['limit'] = limit; // Accepted values: 1 - 1000. If the parameter is not specified, the number of results is limited to 100
}
const response = await this.publicGetOhlcv (this.extend (request, params));
+ //
+ // [
+ // {
+ // "timestamp": "2020-06-06T17:36:00Z",
+ // "open": 0.025,
+ // "high": 0.025,
+ // "low": 0.02499,
+ // "close": 0.02499,
+ // "volume": 0.00643127
+ // }
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -645,21 +660,8 @@ module.exports = class crex24 extends Exchange {
// }
//
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let symbol = undefined;
const marketId = this.safeString (order, 'instrument');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.parse8601 (this.safeString (order, 'timestamp'));
let price = this.safeFloat (order, 'price');
const amount = this.safeFloat (order, 'volume');
@@ -702,6 +704,8 @@ module.exports = class crex24 extends Exchange {
cost = parseFloat (this.costToPrecision (symbol, cost));
}
}
+ const timeInForce = this.safeString (order, 'timeInForce');
+ const stopPrice = this.safeFloat (order, 'stopPrice');
return {
'info': order,
'id': id,
@@ -711,8 +715,10 @@ module.exports = class crex24 extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -762,6 +768,7 @@ module.exports = class crex24 extends Exchange {
} else {
request['stopPrice'] = this.priceToPrecision (symbol, stopPrice);
}
+ params = this.omit (params, 'stopPrice');
}
const response = await this.tradingPostPlaceOrder (this.extend (request, params));
//
@@ -1233,6 +1240,7 @@ module.exports = class crex24 extends Exchange {
// true - balance will be decreased by amount, whereas [amount - fee] will be transferred to the specified address
// false - amount will be deposited to the specified address, whereas the balance will be decreased by [amount + fee]
// 'includeFee': false, // the default value is false
+ 'feeCurrency': currency['id'], // https://github.com/ccxt/ccxt/issues/7544
};
if (tag !== undefined) {
request['paymentId'] = tag;
@@ -1264,8 +1272,7 @@ module.exports = class crex24 extends Exchange {
body = this.json (params);
auth += body;
}
- const signature = this.stringToBase64 (this.hmac (this.encode (auth), secret, 'sha512', 'binary'));
- headers['X-CREX24-API-SIGN'] = this.decode (signature);
+ headers['X-CREX24-API-SIGN'] = this.hmac (this.encode (auth), secret, 'sha512', 'base64');
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/currencycom.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/currencycom.js
new file mode 100644
index 000000000..3914c1bfc
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/currencycom.js
@@ -0,0 +1,1119 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, DDoSProtection, InvalidNonce, AuthenticationError, BadRequest } = require ('./base/errors');
+const { ROUND, TICK_SIZE } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class currencycom extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'currencycom',
+ 'name': 'Currency.com',
+ 'countries': [ 'BY' ], // Belarus
+ 'rateLimit': 500,
+ 'certified': true,
+ 'pro': true,
+ 'version': 'v1',
+ // new metainfo interface
+ 'has': {
+ 'cancelOrder': true,
+ 'CORS': false,
+ 'createOrder': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTradingFees': true,
+ 'fetchTrades': true,
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '3m': '3m',
+ '5m': '5m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '4h': '4h',
+ '1d': '1d',
+ '1w': '1w',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/83718672-36745c00-a63e-11ea-81a9-677b1f789a4d.jpg',
+ 'api': {
+ 'public': 'https://api-adapter.backend.currency.com/api',
+ 'private': 'https://api-adapter.backend.currency.com/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',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'time',
+ 'exchangeInfo',
+ 'depth',
+ 'aggTrades',
+ 'klines',
+ 'ticker/24hr',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'leverageSettings',
+ 'openOrders',
+ 'tradingPositions',
+ 'account',
+ 'myTrades',
+ ],
+ 'post': [
+ 'order',
+ 'updateTradingPosition',
+ 'updateTradingOrder',
+ 'closeTradingPosition',
+ ],
+ 'delete': [
+ 'order',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': false,
+ 'percentage': true,
+ 'taker': 0.002,
+ 'maker': 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',
+ },
+ },
+ '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,
+ },
+ '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, // 'your time is ahead of server'
+ '-1022': AuthenticationError, // {"code":-1022,"msg":"Signature for this request is not valid."}
+ '-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."}
+ '-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': {
+ 'IQ': 'iQIYI',
+ },
+ });
+ }
+
+ nonce () {
+ return this.milliseconds () - this.options['timeDifference'];
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // {
+ // "serverTime": 1590998366609
+ // }
+ //
+ return this.safeInteger (response, 'serverTime');
+ }
+
+ async loadTimeDifference (params = {}) {
+ const response = await this.publicGetTime (params);
+ const after = this.milliseconds ();
+ this.options['timeDifference'] = parseInt (after - response['serverTime']);
+ return this.options['timeDifference'];
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetExchangeInfo (params);
+ //
+ // {
+ // "timezone":"UTC",
+ // "serverTime":1603252990096,
+ // "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":"EVK",
+ // "name":"Evonik",
+ // "status":"BREAK",
+ // "baseAsset":"EVK",
+ // "baseAssetPrecision":3,
+ // "quoteAsset":"EUR",
+ // "quoteAssetId":"EUR",
+ // "quotePrecision":3,
+ // "orderTypes":["LIMIT","MARKET"],
+ // "filters":[
+ // {"filterType":"LOT_SIZE","minQty":"1","maxQty":"27000","stepSize":"1"},
+ // {"filterType":"MIN_NOTIONAL","minNotional":"23"}
+ // ],
+ // "marketType":"SPOT",
+ // "country":"DE",
+ // "sector":"Basic Materials",
+ // "industry":"Diversified Chemicals",
+ // "tradingHours":"UTC; Mon 07:02 - 15:30; Tue 07:02 - 15:30; Wed 07:02 - 15:30; Thu 07:02 - 15:30; Fri 07:02 - 15:30",
+ // "tickSize":0.005,
+ // "tickValue":0.11125,
+ // "exchangeFee":0.05
+ // },
+ // {
+ // "symbol":"BTC/USD_LEVERAGE",
+ // "name":"Bitcoin / USD",
+ // "status":"TRADING",
+ // "baseAsset":"BTC",
+ // "baseAssetPrecision":3,
+ // "quoteAsset":"USD",
+ // "quoteAssetId":"USD_LEVERAGE",
+ // "quotePrecision":3,
+ // "orderTypes":["LIMIT","MARKET","STOP"],
+ // "filters":[
+ // {"filterType":"LOT_SIZE","minQty":"0.001","maxQty":"100","stepSize":"0.001"},
+ // {"filterType":"MIN_NOTIONAL","minNotional":"13"}
+ // ],
+ // "marketType":"LEVERAGE",
+ // "longRate":-0.01,
+ // "shortRate":0.01,
+ // "swapChargeInterval":480,
+ // "country":"",
+ // "sector":"",
+ // "industry":"",
+ // "tradingHours":"UTC; Mon - 21:00, 21:05 -; Tue - 21:00, 21:05 -; Wed - 21:00, 21:05 -; Thu - 21:00, 21:05 -; Fri - 21:00, 22:01 -; Sat - 21:00, 21:05 -; Sun - 20:00, 21:05 -",
+ // "tickSize":0.05,
+ // "tickValue":610.20875,
+ // "makerFee":-0.025,
+ // "takerFee":0.075
+ // },
+ // ]
+ // }
+ //
+ 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;
+ if (id.indexOf ('/') >= 0) {
+ symbol = id;
+ }
+ const filters = this.safeValue (market, 'filters', []);
+ const filtersByType = this.indexBy (filters, 'filterType');
+ const precision = {
+ 'amount': 1 / Math.pow (1, this.safeInteger (market, 'baseAssetPrecision')),
+ 'price': this.safeFloat (market, 'tickSize'),
+ };
+ const status = this.safeString (market, 'status');
+ const active = (status === 'TRADING');
+ let type = this.safeStringLower (market, 'marketType');
+ if (type === 'leverage') {
+ type = 'margin';
+ }
+ const spot = (type === 'spot');
+ const margin = (type === 'margin');
+ const entry = {
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'type': type,
+ 'spot': spot,
+ 'margin': margin,
+ 'info': market,
+ 'active': active,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': Math.pow (10, -precision['amount']),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': -1 * Math.log10 (precision['amount']),
+ 'max': undefined,
+ },
+ },
+ };
+ const exchangeFee = this.safeFloat2 (market, 'exchangeFee', 'tradingFee');
+ const makerFee = this.safeFloat (market, 'makerFee', exchangeFee);
+ const takerFee = this.safeFloat (market, 'takerFee', exchangeFee);
+ if (makerFee !== undefined) {
+ entry['maker'] = makerFee / 100;
+ }
+ if (takerFee !== undefined) {
+ entry['taker'] = takerFee / 100;
+ }
+ if ('PRICE_FILTER' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'PRICE_FILTER', {});
+ entry['precision']['price'] = this.safeFloat (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
+ entry['limits']['price'] = {
+ 'min': this.safeFloat (filter, 'minPrice'),
+ 'max': undefined,
+ };
+ const maxPrice = this.safeFloat (filter, 'maxPrice');
+ if ((maxPrice !== undefined) && (maxPrice > 0)) {
+ entry['limits']['price']['max'] = maxPrice;
+ }
+ }
+ if ('LOT_SIZE' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'LOT_SIZE', {});
+ entry['precision']['amount'] = this.safeFloat (filter, 'stepSize');
+ entry['limits']['amount'] = {
+ 'min': this.safeFloat (filter, 'minQty'),
+ 'max': this.safeFloat (filter, 'maxQty'),
+ };
+ }
+ if ('MARKET_LOT_SIZE' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'MARKET_LOT_SIZE', {});
+ entry['limits']['market'] = {
+ 'min': this.safeFloat (filter, 'minQty'),
+ 'max': this.safeFloat (filter, 'maxQty'),
+ };
+ }
+ if ('MIN_NOTIONAL' in filtersByType) {
+ const filter = this.safeValue (filtersByType, 'MIN_NOTIONAL', {});
+ entry['limits']['cost']['min'] = this.safeFloat (filter, 'minNotional');
+ }
+ result.push (entry);
+ }
+ return result;
+ }
+
+ calculateFee (symbol, type, side, amount, price, takerOrMaker = 'taker', params = {}) {
+ const market = this.markets[symbol];
+ let key = 'quote';
+ const rate = market[takerOrMaker];
+ let cost = amount * rate;
+ let precision = market['precision']['price'];
+ if (side === 'sell') {
+ cost *= price;
+ } else {
+ key = 'base';
+ precision = market['precision']['amount'];
+ }
+ cost = this.decimalToPrecision (cost, ROUND, precision, this.precisionMode);
+ return {
+ 'type': takerOrMaker,
+ 'currency': market[key],
+ 'rate': rate,
+ 'cost': parseFloat (cost),
+ };
+ }
+
+ async fetchAccounts (params = {}) {
+ const response = await this.privateGetAccount (params);
+ //
+ // {
+ // "makerCommission":0.20,
+ // "takerCommission":0.20,
+ // "buyerCommission":0.20,
+ // "sellerCommission":0.20,
+ // "canTrade":true,
+ // "canWithdraw":true,
+ // "canDeposit":true,
+ // "updateTime":1591056268,
+ // "balances":[
+ // {
+ // "accountId":5470306579272968,
+ // "collateralCurrency":true,
+ // "asset":"ETH",
+ // "free":0.0,
+ // "locked":0.0,
+ // "default":false,
+ // },
+ // ]
+ // }
+ //
+ 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': response,
+ });
+ }
+ return result;
+ }
+
+ async fetchTradingFees (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccount (params);
+ return {
+ 'info': response,
+ 'maker': this.safeFloat (response, 'makerCommission'),
+ 'taker': this.safeFloat (response, 'takerCommission'),
+ };
+ }
+
+ parseBalanceResponse (response) {
+ //
+ // {
+ // "makerCommission":0.20,
+ // "takerCommission":0.20,
+ // "buyerCommission":0.20,
+ // "sellerCommission":0.20,
+ // "canTrade":true,
+ // "canWithdraw":true,
+ // "canDeposit":true,
+ // "updateTime":1591056268,
+ // "balances":[
+ // {
+ // "accountId":5470306579272968,
+ // "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.safeFloat (balance, 'free');
+ account['used'] = this.safeFloat (balance, 'locked');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccount (params);
+ //
+ // {
+ // "makerCommission":0.20,
+ // "takerCommission":0.20,
+ // "buyerCommission":0.20,
+ // "sellerCommission":0.20,
+ // "canTrade":true,
+ // "canWithdraw":true,
+ // "canDeposit":true,
+ // "updateTime":1591056268,
+ // "balances":[
+ // {
+ // "accountId":5470306579272968,
+ // "collateralCurrency":true,
+ // "asset":"ETH",
+ // "free":0.0,
+ // "locked":0.0,
+ // "default":false,
+ // },
+ // ]
+ // }
+ //
+ return this.parseBalanceResponse (response);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 100, max 1000, valid limits 5, 10, 20, 50, 100, 500, 1000, 5000
+ }
+ const response = await this.publicGetDepth (this.extend (request, params));
+ //
+ // {
+ // "lastUpdateId":1590999849037,
+ // "asks":[
+ // [0.02495,60.0000],
+ // [0.02496,120.0000],
+ // [0.02497,240.0000],
+ // ],
+ // "bids":[
+ // [0.02487,60.0000],
+ // [0.02486,120.0000],
+ // [0.02485,240.0000],
+ // ]
+ // }
+ //
+ const orderbook = this.parseOrderBook (response);
+ 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":"EVK",
+ // "highPrice":"22.57",
+ // "lowPrice":"22.16",
+ // "volume":"1",
+ // "quoteVolume":"22.2",
+ // "openTime":1590699364000,
+ // "closeTime":1590785764000
+ // }
+ //
+ const timestamp = this.safeInteger (ticker, 'closeTime');
+ const marketId = this.safeString (ticker, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
+ const last = this.safeFloat (ticker, 'lastPrice');
+ const open = this.safeFloat (ticker, 'openPrice');
+ let average = undefined;
+ if ((open !== undefined) && (last !== undefined)) {
+ average = this.sum (open, last) / 2;
+ }
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'highPrice'),
+ 'low': this.safeFloat (ticker, 'lowPrice'),
+ 'bid': this.safeFloat (ticker, 'bidPrice'),
+ 'bidVolume': this.safeFloat (ticker, 'bidQty'),
+ 'ask': this.safeFloat (ticker, 'askPrice'),
+ 'askVolume': this.safeFloat (ticker, 'askQty'),
+ 'vwap': this.safeFloat (ticker, 'weightedAvgPrice'),
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': this.safeFloat (ticker, 'prevClosePrice'), // previous day close
+ 'change': this.safeFloat (ticker, 'priceChange'),
+ 'percentage': this.safeFloat (ticker, 'priceChangePercent'),
+ 'average': average,
+ 'baseVolume': this.safeFloat (ticker, 'volume'),
+ 'quoteVolume': this.safeFloat (ticker, 'quoteVolume'),
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this.publicGetTicker24hr (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);
+ }
+
+ parseTickers (rawTickers, symbols = undefined) {
+ const tickers = [];
+ for (let i = 0; i < rawTickers.length; i++) {
+ tickers.push (this.parseTicker (rawTickers[i]));
+ }
+ return this.filterByArray (tickers, 'symbol', symbols);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetTicker24hr (params);
+ //
+ // [
+ // {
+ // "symbol":"EVK",
+ // "highPrice":"22.57",
+ // "lowPrice":"22.16",
+ // "volume":"1",
+ // "quoteVolume":"22.2",
+ // "openTime":1590699364000,
+ // "closeTime":1590785764000
+ // }
+ // ]
+ //
+ 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.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ 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.publicGetKlines (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,
+ // "p":"0.02476",
+ // "q":"0.0",
+ // "T":1591001423382,
+ // "m":false
+ // }
+ //
+ // createOrder fills (private)
+ //
+ // {
+ // "price": "9807.05",
+ // "qty": "0.01",
+ // "commission": "0",
+ // "commissionAsset": "dUSD"
+ // }
+ //
+ // fetchMyTrades
+ //
+ // {
+ // "symbol": "BNBBTC",
+ // "id": 28457,
+ // "orderId": 100234,
+ // "price": "4.00000100",
+ // "qty": "12.00000000",
+ // "commission": "10.10000000",
+ // "commissionAsset": "BNB",
+ // "time": 1499865549590,
+ // "isBuyer": true,
+ // "isMaker": false,
+ // "isBestMatch": true
+ // }
+ //
+ const timestamp = this.safeInteger2 (trade, 'T', 'time');
+ const price = this.safeFloat2 (trade, 'p', 'price');
+ const amount = this.safeFloat2 (trade, 'q', 'qty');
+ const id = this.safeString2 (trade, 'a', 'id');
+ let side = undefined;
+ const orderId = this.safeString (trade, 'orderId');
+ if ('m' in trade) {
+ side = trade['m'] ? 'sell' : 'buy'; // this is reversed intentionally
+ } else if ('isBuyerMaker' in trade) {
+ side = trade['isBuyerMaker'] ? 'sell' : 'buy';
+ } else {
+ if ('isBuyer' in trade) {
+ side = (trade['isBuyer']) ? 'buy' : 'sell'; // this is a true side
+ }
+ }
+ let fee = undefined;
+ if ('commission' in trade) {
+ fee = {
+ 'cost': this.safeFloat (trade, 'commission'),
+ 'currency': this.safeCurrencyCode (this.safeString (trade, 'commissionAsset')),
+ };
+ }
+ let takerOrMaker = undefined;
+ if ('isMaker' in trade) {
+ takerOrMaker = trade['isMaker'] ? 'maker' : 'taker';
+ }
+ const marketId = this.safeString (trade, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
+ return {
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'id': id,
+ 'order': orderId,
+ 'type': undefined,
+ 'takerOrMaker': takerOrMaker,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': price * amount,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ 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
+ }
+ const response = await this.publicGetAggTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "a":1658318071,
+ // "p":"0.02476",
+ // "q":"0.0",
+ // "T":1591001423382,
+ // "m":false
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'NEW': 'open',
+ 'PARTIALLY_FILLED': 'open',
+ 'FILLED': 'closed',
+ 'CANCELED': 'canceled',
+ 'PENDING_CANCEL': 'canceling', // currently unused
+ 'REJECTED': 'rejected',
+ 'EXPIRED': 'expired',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // {
+ // "symbol": "BTC/USD",
+ // "orderId": "00000000-0000-0000-0000-0000000c0263",
+ // "clientOrderId": "00000000-0000-0000-0000-0000000c0263",
+ // "transactTime": 1589878206426,
+ // "price": "9825.66210000",
+ // "origQty": "0.01",
+ // "executedQty": "0.01",
+ // "status": "FILLED",
+ // "timeInForce": "FOK",
+ // "type": "MARKET",
+ // "side": "BUY",
+ // "fills": [
+ // {
+ // "price": "9807.05",
+ // "qty": "0.01",
+ // "commission": "0",
+ // "commissionAsset": "dUSD"
+ // }
+ // ]
+ // }
+ //
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '/');
+ let timestamp = undefined;
+ if ('time' in order) {
+ timestamp = this.safeInteger (order, 'time');
+ } else if ('transactTime' in order) {
+ timestamp = this.safeInteger (order, 'transactTime');
+ }
+ let price = this.safeFloat (order, 'price');
+ const amount = this.safeFloat (order, 'origQty');
+ const filled = this.safeFloat (order, 'executedQty');
+ let remaining = undefined;
+ let cost = this.safeFloat (order, 'cummulativeQuoteQty');
+ if (filled !== undefined) {
+ if (amount !== undefined) {
+ remaining = amount - filled;
+ if (this.options['parseOrderToPrecision']) {
+ remaining = parseFloat (this.amountToPrecision (symbol, remaining));
+ }
+ remaining = Math.max (remaining, 0.0);
+ }
+ if (price !== undefined) {
+ if (cost === undefined) {
+ cost = price * filled;
+ }
+ }
+ }
+ const id = this.safeString (order, 'orderId');
+ const type = this.safeStringLower (order, 'type');
+ if (type === 'market') {
+ if (price === 0.0) {
+ if ((cost !== undefined) && (filled !== undefined)) {
+ if ((cost > 0) && (filled > 0)) {
+ price = cost / filled;
+ }
+ }
+ }
+ }
+ const side = this.safeStringLower (order, 'side');
+ let fee = undefined;
+ let trades = undefined;
+ const fills = this.safeValue (order, 'fills');
+ if (fills !== undefined) {
+ trades = this.parseTrades (fills, market);
+ const numTrades = trades.length;
+ if (numTrades > 0) {
+ cost = trades[0]['cost'];
+ fee = {
+ 'cost': trades[0]['fee']['cost'],
+ 'currency': trades[0]['fee']['currency'],
+ };
+ for (let i = 1; i < trades.length; i++) {
+ cost = this.sum (cost, trades[i]['cost']);
+ fee['cost'] = this.sum (fee['cost'], trades[i]['fee']['cost']);
+ }
+ }
+ }
+ let average = undefined;
+ if (cost !== undefined) {
+ if (filled) {
+ average = cost / filled;
+ }
+ if (this.options['parseOrderToPrecision']) {
+ cost = parseFloat (this.costToPrecision (symbol, cost));
+ }
+ }
+ const timeInForce = this.safeString (order, 'timeInForce');
+ return {
+ 'info': order,
+ 'id': id,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': timeInForce,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': trades,
+ };
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ let accountId = undefined;
+ if (market['margin']) {
+ accountId = this.safeInteger (params, 'accountId');
+ if (accountId === undefined) {
+ throw new ArgumentsRequired (this.id + ' createOrder requires an accountId parameter for ' + market['type'] + ' market ' + symbol);
+ }
+ }
+ const uppercaseType = type.toUpperCase ();
+ const newOrderRespType = this.safeValue (this.options['newOrderRespType'], type, 'RESULT');
+ const request = {
+ 'symbol': market['id'],
+ 'quantity': this.amountToPrecision (symbol, amount),
+ 'type': uppercaseType,
+ 'side': side.toUpperCase (),
+ 'newOrderRespType': newOrderRespType, // 'RESULT' for full order or 'FULL' for order with fills
+ // 'leverage': 1,
+ // 'accountId': 5470306579272968, // required for leverage markets
+ // 'takeProfit': '123.45',
+ // 'stopLoss': '54.321'
+ // 'guaranteedStopLoss': '54.321',
+ };
+ if (uppercaseType === 'LIMIT') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ request['timeInForce'] = this.options['defaultTimeInForce']; // 'GTC' = Good To Cancel (default), 'IOC' = Immediate Or Cancel, 'FOK' = Fill Or Kill
+ } else if (uppercaseType === 'STOP') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
+ const response = await this.privatePostOrder (this.extend (request, params));
+ //
+ // {
+ // "symbol": "BTC/USD",
+ // "orderId": "00000000-0000-0000-0000-0000000c0263",
+ // "clientOrderId": "00000000-0000-0000-0000-0000000c0263",
+ // "transactTime": 1589878206426,
+ // "price": "9825.66210000",
+ // "origQty": "0.01",
+ // "executedQty": "0.01",
+ // "status": "FILLED",
+ // "timeInForce": "FOK",
+ // "type": "MARKET",
+ // "side": "BUY",
+ // "fills": [
+ // {
+ // "price": "9807.05",
+ // "qty": "0.01",
+ // "commission": "0",
+ // "commissionAsset": "dUSD"
+ // }
+ // ]
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let market = undefined;
+ const request = {};
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ } else if (this.options['warnOnFetchOpenOrdersWithoutSymbol']) {
+ const symbols = this.symbols;
+ const numSymbols = symbols.length;
+ const fetchOpenOrdersRateLimit = parseInt (numSymbols / 2);
+ throw new ExchangeError (this.id + ' fetchOpenOrders WARNING: fetching open orders without specifying a symbol is rate-limited to one call per ' + fetchOpenOrdersRateLimit.toString () + ' seconds. Do not call this method frequently to avoid ban. Set ' + this.id + '.options["warnOnFetchOpenOrdersWithoutSymbol"] = false to suppress this warning message.');
+ }
+ const response = await this.privateGetOpenOrders (this.extend (request, params));
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' cancelOrder requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const origClientOrderId = this.safeValue (params, 'origClientOrderId');
+ const request = {
+ 'symbol': market['id'],
+ // 'orderId': parseInt (id),
+ // 'origClientOrderId': id,
+ };
+ if (origClientOrderId === undefined) {
+ request['orderId'] = id;
+ } else {
+ request['origClientOrderId'] = origClientOrderId;
+ }
+ const response = await this.privateDeleteOrder (this.extend (request, params));
+ //
+ // {
+ // "symbol":"ETH/USD",
+ // "orderId":"00000000-0000-0000-0000-00000024383b",
+ // "clientOrderId":"00000000-0000-0000-0000-00000024383b",
+ // "price":"150",
+ // "origQty":"0.1",
+ // "executedQty":"0.0",
+ // "status":"CANCELED",
+ // "timeInForce":"GTC",
+ // "type":"LIMIT",
+ // "side":"BUY"
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchMyTrades requires a symbol argument');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetMyTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "symbol": "BNBBTC",
+ // "id": 28457,
+ // "orderId": 100234,
+ // "price": "4.00000100",
+ // "qty": "12.00000000",
+ // "commission": "10.10000000",
+ // "commissionAsset": "BNB",
+ // "time": 1499865549590,
+ // "isBuyer": true,
+ // "isMaker": false,
+ // "isBestMatch": true
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ let url = this.urls['api'][api] + '/' + this.version + '/' + path;
+ if (path === 'historicalTrades') {
+ headers = {
+ 'X-MBX-APIKEY': this.apiKey,
+ };
+ }
+ if (api === 'private') {
+ this.checkRequiredCredentials ();
+ let query = this.urlencode (this.extend ({
+ 'timestamp': this.nonce (),
+ 'recvWindow': this.options['recvWindow'],
+ }, params));
+ const signature = this.hmac (this.encode (query), this.encode (this.secret));
+ query += '&' + 'signature=' + signature;
+ headers = {
+ 'X-MBX-APIKEY': this.apiKey,
+ };
+ if ((method === 'GET') || (method === 'DELETE')) {
+ url += '?' + query;
+ } else {
+ body = query;
+ headers['Content-Type'] = 'application/x-www-form-urlencoded';
+ }
+ } else {
+ if (Object.keys (params).length) {
+ url += '?' + this.urlencode (params);
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if ((httpCode === 418) || (httpCode === 429)) {
+ throw new DDoSProtection (this.id + ' ' + httpCode.toString () + ' ' + reason + ' ' + body);
+ }
+ // error response in a form: { "code": -1013, "msg": "Invalid quantity." }
+ // following block cointains legacy checks against message patterns in "msg" property
+ // will switch "code" checks eventually, when we know all of them
+ if (httpCode >= 400) {
+ if (body.indexOf ('Price * QTY is zero or less') >= 0) {
+ throw new InvalidOrder (this.id + ' order cost = amount * price is zero or less ' + body);
+ }
+ if (body.indexOf ('LOT_SIZE') >= 0) {
+ throw new InvalidOrder (this.id + ' order amount should be evenly divisible by lot size ' + body);
+ }
+ if (body.indexOf ('PRICE_FILTER') >= 0) {
+ throw new InvalidOrder (this.id + ' order price is invalid, i.e. exceeds allowed price precision, exceeds min price or max price limits or is invalid float value in general, use this.priceToPrecision (symbol, amount) ' + body);
+ }
+ }
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ //
+ // {"code":-1128,"msg":"Combination of optional parameters invalid."}
+ //
+ const errorCode = this.safeString (response, 'code');
+ if ((errorCode !== undefined) && (errorCode !== '0')) {
+ const feedback = this.id + ' ' + this.json (response);
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ const message = this.safeString (response, 'msg');
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback);
+ }
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/deribit.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/deribit.js
similarity index 94%
rename from TaskServer/node_modules/ccxt/js/deribit.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/deribit.js
index 6f4827691..9f88f869b 100644
--- a/TaskServer/node_modules/ccxt/js/deribit.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/deribit.js
@@ -18,28 +18,32 @@ module.exports = class deribit extends Exchange {
'userAgent': undefined,
'rateLimit': 500,
'has': {
+ 'cancelAllOrders': true,
+ 'cancelOrder': true,
'CORS': true,
+ 'createDepositAddress': true,
+ 'createOrder': true,
'editOrder': true,
'fetchBalance': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
'fetchClosedOrders': true,
- 'fetchMyTrades': true,
- 'fetchTickers': true,
- 'fetchOHLCV': true,
'fetchDepositAddress': true,
- 'createDepositAddress': true,
- 'fetchOrderTrades': true,
- 'createOrder': true,
- 'cancelOrder': true,
- 'cancelAllOrders': true,
- 'withdraw': true,
- 'fetchTime': true,
- 'fetchStatus': true,
'fetchDeposits': true,
- 'fetchWithdrawals': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchOrderTrades': true,
+ 'fetchStatus': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTransactions': false,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1',
@@ -649,13 +653,7 @@ module.exports = class deribit extends Exchange {
//
const timestamp = this.safeInteger2 (ticker, 'timestamp', 'creation_timestamp');
const marketId = this.safeString (ticker, 'instrument_name');
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const last = this.safeFloat2 (ticker, 'last_price', 'last');
const stats = this.safeValue (ticker, 'stats', ticker);
return {
@@ -860,15 +858,8 @@ module.exports = class deribit extends Exchange {
// }
//
const id = this.safeString (trade, 'trade_id');
- let symbol = undefined;
const marketId = this.safeString (trade, 'instrument_name');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.safeInteger (trade, 'timestamp');
const side = this.safeString (trade, 'direction');
const price = this.safeFloat (trade, 'price');
@@ -1025,6 +1016,15 @@ module.exports = class deribit extends Exchange {
return this.safeString (statuses, status, status);
}
+ parseTimeInForce (timeInForce) {
+ const timeInForces = {
+ 'good_til_cancelled': 'GTC',
+ 'fill_or_kill': 'FOK',
+ 'immediate_or_cancel': 'IOC',
+ };
+ return this.safeString (timeInForces, timeInForce, timeInForce);
+ }
+
parseOrder (order, market = undefined) {
//
// createOrder
@@ -1078,21 +1078,7 @@ module.exports = class deribit extends Exchange {
}
const status = this.parseOrderStatus (this.safeString (order, 'order_state'));
const marketId = this.safeString (order, 'instrument_name');
- let symbol = undefined;
- let base = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- base = market['base'];
- }
- if (market !== undefined) {
- if (symbol === undefined) {
- symbol = market['symbol'];
- }
- if (base === undefined) {
- base = market['base'];
- }
- }
+ market = this.safeMarket (marketId, market);
const side = this.safeStringLower (order, 'direction');
let feeCost = this.safeFloat (order, 'commission');
let fee = undefined;
@@ -1100,7 +1086,7 @@ module.exports = class deribit extends Exchange {
feeCost = Math.abs (feeCost);
fee = {
'cost': feeCost,
- 'currency': base,
+ 'currency': market['base'],
};
}
const type = this.safeString (order, 'order_type');
@@ -1109,6 +1095,8 @@ module.exports = class deribit extends Exchange {
if (trades !== undefined) {
trades = this.parseTrades (trades, market);
}
+ const timeInForce = this.parseTimeInForce (this.safeString (order, 'time_in_force'));
+ const stopPrice = undefined;
return {
'info': order,
'id': id,
@@ -1116,10 +1104,12 @@ module.exports = class deribit extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -1211,6 +1201,7 @@ module.exports = class deribit extends Exchange {
} else {
request['stop_price'] = this.priceToPrecision (symbol, stopPrice);
}
+ params = this.omit (params, [ 'stop_price', 'stopPrice' ]);
}
const method = 'privateGet' + this.capitalize (side);
const response = await this[method] (this.extend (request, params));
@@ -1634,6 +1625,86 @@ module.exports = class deribit extends Exchange {
};
}
+ async fetchPosition (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'instrument_name': market['id'],
+ };
+ const response = await this.privateGetPosition (this.extend (request, params));
+ //
+ // {
+ // "jsonrpc": "2.0",
+ // "id": 404,
+ // "result": {
+ // "average_price": 0,
+ // "delta": 0,
+ // "direction": "buy",
+ // "estimated_liquidation_price": 0,
+ // "floating_profit_loss": 0,
+ // "index_price": 3555.86,
+ // "initial_margin": 0,
+ // "instrument_name": "BTC-PERPETUAL",
+ // "leverage": 100,
+ // "kind": "future",
+ // "maintenance_margin": 0,
+ // "mark_price": 3556.62,
+ // "open_orders_margin": 0.000165889,
+ // "realized_profit_loss": 0,
+ // "settlement_price": 3555.44,
+ // "size": 0,
+ // "size_currency": 0,
+ // "total_profit_loss": 0
+ // }
+ // }
+ //
+ // todo unify parsePosition/parsePositions
+ const result = this.safeValue (response, 'result');
+ return result;
+ }
+
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const code = this.codeFromOptions ('fetchPositions');
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privateGetPositions (this.extend (request, params));
+ //
+ // {
+ // "jsonrpc": "2.0",
+ // "id": 2236,
+ // "result": [
+ // {
+ // "average_price": 7440.18,
+ // "delta": 0.006687487,
+ // "direction": "buy",
+ // "estimated_liquidation_price": 1.74,
+ // "floating_profit_loss": 0,
+ // "index_price": 7466.79,
+ // "initial_margin": 0.000197283,
+ // "instrument_name": "BTC-PERPETUAL",
+ // "kind": "future",
+ // "leverage": 34,
+ // "maintenance_margin": 0.000143783,
+ // "mark_price": 7476.65,
+ // "open_orders_margin": 0.000197288,
+ // "realized_funding": -1e-8,
+ // "realized_profit_loss": -9e-9,
+ // "settlement_price": 7476.65,
+ // "size": 50,
+ // "size_currency": 0.006687487,
+ // "total_profit_loss": 0.000032781
+ // }
+ // ]
+ // }
+ //
+ // todo unify parsePosition/parsePositions
+ const result = this.safeValue (response, 'result', []);
+ return result;
+ }
+
async withdraw (code, amount, address, tag = undefined, params = {}) {
this.checkAddress (address);
await this.loadMarkets ();
diff --git a/TaskServer/node_modules/ccxt/js/digifinex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/digifinex.js
similarity index 70%
rename from TaskServer/node_modules/ccxt/js/digifinex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/digifinex.js
index 53c23d198..25a9fcabb 100644
--- a/TaskServer/node_modules/ccxt/js/digifinex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/digifinex.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { AccountSuspended, BadRequest, BadResponse, NetworkError, DDoSProtection, AuthenticationError, PermissionDenied, ArgumentsRequired, ExchangeError, InsufficientFunds, InvalidOrder, InvalidNonce, OrderNotFound } = require ('./base/errors');
+const { AccountSuspended, BadRequest, BadResponse, NetworkError, DDoSProtection, AuthenticationError, PermissionDenied, ArgumentsRequired, ExchangeError, InsufficientFunds, InvalidOrder, InvalidNonce, OrderNotFound, InvalidAddress, RateLimitExceeded, BadSymbol } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -16,14 +16,28 @@ module.exports = class digifinex extends Exchange {
'version': 'v3',
'rateLimit': 900, // 300 for posts
'has': {
+ 'cancelOrder': true,
'cancelOrders': true,
- 'fetchOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchStatus': true,
+ 'fetchTicker': true,
'fetchTickers': true,
- 'fetchMyTrades': true,
- 'fetchLedger': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1',
@@ -37,14 +51,14 @@ module.exports = class digifinex extends Exchange {
'1w': '1W',
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/62184319-304e8880-b366-11e9-99fe-8011d6929195.jpg',
- 'api': 'https://openapi.digifinex.vip',
- 'www': 'https://www.digifinex.vip',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87443315-01283a00-c5fe-11ea-8628-c2a0feaf07ac.jpg',
+ 'api': 'https://openapi.digifinex.com',
+ 'www': 'https://www.digifinex.com',
'doc': [
- 'https://docs.digifinex.vip',
+ 'https://docs.digifinex.com',
],
'fees': 'https://digifinex.zendesk.com/hc/en-us/articles/360000328422-Fee-Structure-on-DigiFinex',
- 'referral': 'https://www.digifinex.vip/en-ww/from/DhOzBg/3798****5114',
+ 'referral': 'https://www.digifinex.com/en-ww/from/DhOzBg?channelCode=ljaUPp',
},
'api': {
'v2': {
@@ -58,12 +72,15 @@ module.exports = class digifinex extends Exchange {
'kline',
'margin/currencies',
'margin/symbols',
- 'markets', // undocumented
+ 'markets',
'order_book',
'ping',
'spot/symbols',
'time',
'trades',
+ 'trades/symbols',
+ 'ticker',
+ 'currencies', // todo add fetchCurrencies
],
},
'private': {
@@ -71,6 +88,7 @@ module.exports = class digifinex extends Exchange {
'{market}/financelog',
'{market}/mytrades',
'{market}/order',
+ '{market}/order/detail', // todo add fetchOrder
'{market}/order/current',
'{market}/order/history',
'margin/assets',
@@ -87,16 +105,22 @@ module.exports = class digifinex extends Exchange {
'spot/order',
'spot/order/current',
'spot/order/history',
+ 'deposit/address', // todo add fetchDepositAddress
+ 'deposit/history', // todo add fetchDeposits
+ 'withdraw/history', // todo add fetchWithdrawals
],
'post': [
'{market}/order/cancel',
'{market}/order/new',
+ '{market}/order/batch_new',
'margin/order/cancel',
'margin/order/new',
'margin/position/close',
'spot/order/cancel',
'spot/order/new',
'transfer',
+ 'withdraw/new', // todo add withdraw()
+ 'withdraw/cancel',
],
},
},
@@ -136,6 +160,27 @@ module.exports = class digifinex extends Exchange {
'20019': [ BadRequest, 'Wrong trading pair symbol. Correct format:"usdt_btc". Quote asset is in the front' ],
'20020': [ DDoSProtection, "You have violated the API operation trading rules and temporarily forbid trading. At present, we have certain restrictions on the user's transaction rate and withdrawal rate." ],
'50000': [ ExchangeError, 'Exception error' ],
+ '20021': [ BadRequest, 'Invalid currency' ],
+ '20022': [ BadRequest, 'The ending timestamp must be larger than the starting timestamp' ],
+ '20023': [ BadRequest, 'Invalid transfer type' ],
+ '20024': [ BadRequest, 'Invalid amount' ],
+ '20025': [ BadRequest, 'This currency is not transferable at the moment' ],
+ '20026': [ InsufficientFunds, 'Transfer amount exceed your balance' ],
+ '20027': [ PermissionDenied, 'Abnormal account status' ],
+ '20028': [ PermissionDenied, 'Blacklist for transfer' ],
+ '20029': [ PermissionDenied, 'Transfer amount exceed your daily limit' ],
+ '20030': [ BadRequest, 'You have no position on this trading pair' ],
+ '20032': [ PermissionDenied, 'Withdrawal limited' ],
+ '20033': [ BadRequest, 'Wrong Withdrawal ID' ],
+ '20034': [ PermissionDenied, 'Withdrawal service of this crypto has been closed' ],
+ '20035': [ PermissionDenied, 'Withdrawal limit' ],
+ '20036': [ ExchangeError, 'Withdrawal cancellation failed' ],
+ '20037': [ InvalidAddress, 'The withdrawal address, Tag or chain type is not included in the withdrawal management list' ],
+ '20038': [ InvalidAddress, 'The withdrawal address is not on the white list' ],
+ '20039': [ ExchangeError, "Can't be canceled in current status" ],
+ '20040': [ RateLimitExceeded, 'Withdraw too frequently; limitation: 3 times a minute, 100 times a day' ],
+ '20041': [ PermissionDenied, 'Beyond the daily withdrawal limit' ],
+ '20042': [ BadSymbol, 'Current trading pair does not support API trading' ],
},
'broad': {
},
@@ -146,34 +191,130 @@ module.exports = class digifinex extends Exchange {
},
'commonCurrencies': {
'BHT': 'Black House Test',
+ 'MBN': 'Mobilian Coin',
+ 'TEL': 'TEL666',
},
});
}
- async fetchMarketsByType (type, params = {}) {
- const method = 'publicGet' + this.capitalize (type) + 'Symbols';
- const response = await this[method] (params);
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCurrencies (params);
//
// {
- // "symbol_list": [
+ // "data":[
+ // {
+ // "deposit_status":1,
+ // "min_deposit_amount":10,
+ // "withdraw_fee_rate":0,
+ // "min_withdraw_amount":10,
+ // "min_withdraw_fee":5,
+ // "currency":"USDT",
+ // "withdraw_status":0,
+ // "chain":"OMNI"
+ // },
+ // {
+ // "deposit_status":1,
+ // "min_deposit_amount":10,
+ // "withdraw_fee_rate":0,
+ // "min_withdraw_amount":10,
+ // "min_withdraw_fee":3,
+ // "currency":"USDT",
+ // "withdraw_status":1,
+ // "chain":"ERC20"
+ // },
+ // {
+ // "deposit_status":0,
+ // "min_deposit_amount":0,
+ // "withdraw_fee_rate":0,
+ // "min_withdraw_amount":0,
+ // "min_withdraw_fee":0,
+ // "currency":"DGF13",
+ // "withdraw_status":0,
+ // "chain":""
+ // },
+ // ],
+ // "code":200
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = {};
+ for (let i = 0; i < data.length; i++) {
+ const currency = data[i];
+ const id = this.safeString (currency, 'currency');
+ const code = this.safeCurrencyCode (id);
+ const depositStatus = this.safeValue (currency, 'deposit_status', 1);
+ const withdrawStatus = this.safeValue (currency, 'withdraw_status', 1);
+ const active = depositStatus && withdrawStatus;
+ const fee = this.safeFloat (currency, 'withdraw_fee_rate');
+ if (code in result) {
+ if (Array.isArray (result[code]['info'])) {
+ result[code]['info'].push (currency);
+ } else {
+ result[code]['info'] = [ result[code]['info'], currency ];
+ }
+ } else {
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'info': currency,
+ 'type': undefined,
+ 'name': undefined,
+ 'active': active,
+ 'fee': fee,
+ 'precision': 8, // todo fix hardcoded value
+ 'limits': {
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (currency, 'min_withdraw_amount'),
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ }
+ return result;
+ }
+
+ async fetchMarkets (params = {}) {
+ const options = this.safeValue (this.options, 'fetchMarkets', {});
+ const method = this.safeString (options, 'method', 'fetch_markets_v2');
+ return await this[method] (params);
+ }
+
+ async fetchMarketsV2 (params = {}) {
+ const response = await this.publicGetTradesSymbols (params);
+ //
+ // {
+ // "symbol_list":[
// {
// "order_types":["LIMIT","MARKET"],
// "quote_asset":"USDT",
// "minimum_value":2,
// "amount_precision":4,
// "status":"TRADING",
- // "minimum_amount":0.001,
- // "symbol":"LTC_USDT",
- // "margin_rate":0.3,
+ // "minimum_amount":0.0001,
+ // "symbol":"BTC_USDT",
+ // "is_allow":1,
// "zone":"MAIN",
- // "base_asset":"LTC",
+ // "base_asset":"BTC",
// "price_precision":2
- // },
+ // }
// ],
// "code":0
// }
//
- const markets = this.safeValue (response, 'symbols_list', []);
+ const markets = this.safeValue (response, 'symbol_list', []);
const result = [];
for (let i = 0; i < markets.length; i++) {
const market = markets[i];
@@ -211,7 +352,9 @@ module.exports = class digifinex extends Exchange {
// const status = this.safeString (market, 'status');
// const active = (status === 'TRADING');
//
- const active = undefined;
+ const isAllowed = this.safeValue (market, 'is_allow', 1);
+ const active = isAllowed ? true : false;
+ const type = 'spot';
const spot = (type === 'spot');
const margin = (type === 'margin');
result.push ({
@@ -233,7 +376,7 @@ module.exports = class digifinex extends Exchange {
return result;
}
- async fetchMarkets (params = {}) {
+ async fetchMarketsV1 (params = {}) {
const response = await this.publicGetMarkets (params);
//
// {
@@ -394,20 +537,12 @@ module.exports = class digifinex extends Exchange {
'date': date,
}, tickers[reversedMarketId]);
const [ quoteId, baseId ] = reversedMarketId.split ('_');
- const marketId = baseId + '_' + quoteId;
- let market = undefined;
- let symbol = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ const marketId = baseId.toUpperCase () + '_' + quoteId.toUpperCase ();
+ const market = this.safeMarket (marketId, undefined, '_');
+ const symbol = market['symbol'];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -418,7 +553,7 @@ module.exports = class digifinex extends Exchange {
await this.loadMarkets ();
const market = this.market (symbol);
// reversed base/quote in v2
- const marketId = market['quoteId'] + '_' + market['baseId'];
+ const marketId = market['quoteId'].toLowerCase () + '_' + market['baseId'].toLowerCase ();
const request = {
'symbol': marketId,
'apiKey': apiKey,
@@ -535,24 +670,8 @@ module.exports = class digifinex extends Exchange {
cost = price * amount;
}
}
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[market];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const takerOrMaker = this.safeValue (trade, 'is_maker');
const feeCost = this.safeFloat (trade, 'fee');
let fee = undefined;
@@ -581,6 +700,32 @@ module.exports = class digifinex extends Exchange {
};
}
+ async fetchTime (params = {}) {
+ const response = await this.publicGetTime (params);
+ //
+ // {
+ // "server_time": 1589873762,
+ // "code": 0
+ // }
+ //
+ return this.safeTimestamp (response, 'server_time');
+ }
+
+ async fetchStatus (params = {}) {
+ await this.publicGetPing (params);
+ //
+ // {
+ // "msg": "pong",
+ // "code": 0
+ // }
+ //
+ this.status = this.extend (this.status, {
+ 'status': 'ok',
+ 'updated': this.milliseconds (),
+ });
+ return this.status;
+ }
+
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -617,14 +762,24 @@ module.exports = class digifinex extends Exchange {
return this.parseTrades (data, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1556712900,
+ // 2205.899,
+ // 0.029967,
+ // 0.02997,
+ // 0.029871,
+ // 0.029927
+ // ]
+ //
return [
- ohlcv[0] * 1000, // timestamp
- ohlcv[5], // open
- ohlcv[3], // high
- ohlcv[4], // low
- ohlcv[2], // close
- ohlcv[1], // volume
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 5), // open
+ this.safeFloat (ohlcv, 3), // high
+ this.safeFloat (ohlcv, 4), // low
+ this.safeFloat (ohlcv, 2), // close
+ this.safeFloat (ohlcv, 1), // volume
];
}
@@ -813,25 +968,8 @@ module.exports = class digifinex extends Exchange {
}
}
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- if (market === undefined) {
- const exchange = order['symbol'].toUpperCase ();
- if (exchange in this.markets_by_id) {
- market = this.markets_by_id[exchange];
- }
- }
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('_');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const amount = this.safeFloat (order, 'amount');
const filled = this.safeFloat (order, 'executed_amount');
const price = this.safeFloat (order, 'price');
@@ -855,8 +993,10 @@ module.exports = class digifinex extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': filled,
'remaining': remaining,
@@ -987,8 +1127,12 @@ module.exports = class digifinex extends Exchange {
// ]
// }
//
- const data = this.safeValue (response, 'data', {});
- return this.parseOrder (data, market);
+ const data = this.safeValue (response, 'data', []);
+ const order = this.safeValue (data, 0);
+ if (order === undefined) {
+ throw new OrderNotFound (this.id + ' fetchOrder() order ' + id + ' not found');
+ }
+ return this.parseOrder (order, market);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -1118,6 +1262,218 @@ module.exports = class digifinex extends Exchange {
return this.parseLedger (items, currency, since, limit);
}
+ parseDepositAddresses (addresses) {
+ const result = {};
+ for (let i = 0; i < addresses.length; i++) {
+ const address = this.parseDepositAddress (addresses[i]);
+ const code = address['currency'];
+ result[code] = address;
+ }
+ return result;
+ }
+
+ parseDepositAddress (depositAddress, currency = undefined) {
+ //
+ // {
+ // "addressTag":"",
+ // "address":"0xf1104d9f8624f89775a3e9d480fc0e75a8ef4373",
+ // "currency":"USDT",
+ // "chain":"ERC20"
+ // }
+ //
+ const address = this.safeString (depositAddress, 'address');
+ const tag = this.safeString (depositAddress, 'addressTag');
+ const currencyId = this.safeStringUpper (depositAddress, 'currency');
+ const code = this.safeCurrencCode (currencyId);
+ return {
+ 'info': depositAddress,
+ 'code': code,
+ 'address': address,
+ 'tag': tag,
+ };
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'currency': currency['id'],
+ };
+ const response = await this.privateGetDepositAddress (this.extend (request, params));
+ //
+ // {
+ // "data":[
+ // {
+ // "addressTag":"",
+ // "address":"0xf1104d9f8624f89775a3e9d480fc0e75a8ef4373",
+ // "currency":"USDT",
+ // "chain":"ERC20"
+ // }
+ // ],
+ // "code":200
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const addresses = this.parseDepositAddresses (data);
+ const address = this.safeValue (addresses, code);
+ if (address === undefined) {
+ throw new InvalidAddress (this.id + ' fetchDepositAddress did not return an address for ' + code + ' - create the deposit address in the user settings on the exchange website first.');
+ }
+ return address;
+ }
+
+ async fetchTransactionsByType (type, code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let currency = undefined;
+ const request = {
+ // 'currency': currency['id'],
+ // 'from': 'fromId', // When direct is' prev ', from is 1, returning from old to new ascending, when direct is' next ', from is the ID of the most recent record, returned from the old descending order
+ // 'size': 100, // default 100, max 500
+ // 'direct': 'prev', // "prev" ascending, "next" descending
+ };
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency'] = currency['id'];
+ }
+ if (limit !== undefined) {
+ request['size'] = Math.min (500, limit);
+ }
+ const method = (type === 'deposit') ? 'privateGetDepositHistory' : 'privateGetWithdrawHistory';
+ const response = await this[method] (this.extend (request, params));
+ //
+ // {
+ // "code": 200,
+ // "data": [
+ // {
+ // "id": 1171,
+ // "currency": "xrp",
+ // "hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
+ // "chain": "",
+ // "amount": 7.457467,
+ // "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
+ // "memo": "100040",
+ // "fee": 0,
+ // "state": "safe",
+ // "created_date": "2020-04-20 11:23:00",
+ // "finished_date": "2020-04-20 13:23:00"
+ // },
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTransactions (data, currency, since, limit, { 'type': type });
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsByType ('deposit', code, since, limit, params);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchTransactionsByType ('withdrawal', code, since, limit, params);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ '0': 'pending', // Email Sent
+ '1': 'canceled', // Cancelled (different from 1 = ok in deposits)
+ '2': 'pending', // Awaiting Approval
+ '3': 'failed', // Rejected
+ '4': 'pending', // Processing
+ '5': 'failed', // Failure
+ '6': 'ok', // Completed
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // withdraw
+ //
+ // {
+ // "code": 200,
+ // "withdraw_id": 700
+ // }
+ //
+ // fetchDeposits, fetchWithdrawals
+ //
+ // {
+ // "id": 1171,
+ // "currency": "xrp",
+ // "hash": "ed03094b84eafbe4bc16e7ef766ee959885ee5bcb265872baaa9c64e1cf86c2b",
+ // "chain": "",
+ // "amount": 7.457467,
+ // "address": "rae93V8d2mdoUQHwBDBdM4NHCMehRJAsbm",
+ // "memo": "100040",
+ // "fee": 0,
+ // "state": "safe",
+ // "created_date": "2020-04-20 11:23:00",
+ // "finished_date": "2020-04-20 13:23:00"
+ // }
+ //
+ const id = this.safeString2 (transaction, 'id', 'withdraw_id');
+ const address = this.safeString (transaction, 'address');
+ let tag = this.safeString (transaction, 'memo'); // set but unused
+ if (tag !== undefined) {
+ if (tag.length < 1) {
+ tag = undefined;
+ }
+ }
+ const txid = this.safeString (transaction, 'hash');
+ const currencyId = this.safeStringUpper (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const timestamp = this.parse8601 (this.safeString (transaction, 'created_date'));
+ const updated = this.parse8601 (this.safeString (transaction, 'finished_date'));
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'state'));
+ const amount = this.safeFloat (transaction, 'amount');
+ const feeCost = this.safeFloat (transaction, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ fee = { 'currency': code, 'cost': feeCost };
+ }
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'address': address,
+ 'addressTo': address,
+ 'addressFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'tagFrom': undefined,
+ 'type': undefined,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': updated,
+ 'fee': fee,
+ };
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ // 'chain': 'ERC20', 'OMNI', 'TRC20', // required for USDT
+ 'address': address,
+ 'amount': parseFloat (amount),
+ 'currency': currency['id'],
+ };
+ if (tag !== undefined) {
+ request['memo'] = tag;
+ }
+ const response = await this.privatePostWithdrawNew (this.extend (request, params));
+ //
+ // {
+ // "code": 200,
+ // "withdraw_id": 700
+ // }
+ //
+ return this.parseTransaction (response, currency);
+ }
+
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
const version = (api === 'v2') ? api : this.version;
let url = this.urls['api'] + '/' + version + '/' + this.implodeParams (path, params);
@@ -1153,17 +1509,12 @@ module.exports = class digifinex extends Exchange {
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
- dateUTC8 (timestampMS) {
- const timedelta = this.safeValue (this.options, 'timedelta', 8 * 60 * 60 * 1000); // eight hours
- return this.ymd (timestampMS + timedelta);
- }
-
handleErrors (statusCode, statusText, url, method, responseHeaders, responseBody, response, requestHeaders, requestBody) {
if (!response) {
return; // fall back to default error handler
}
const code = this.safeString (response, 'code');
- if (code === '0') {
+ if ((code === '0') || (code === '200')) {
return; // no error
}
const feedback = this.id + ' ' + responseBody;
diff --git a/TaskServer/node_modules/ccxt/js/dsx.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/dsx.js
similarity index 97%
rename from TaskServer/node_modules/ccxt/js/dsx.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/dsx.js
index b8aca2bbb..cff6ab255 100644
--- a/TaskServer/node_modules/ccxt/js/dsx.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/dsx.js
@@ -16,31 +16,38 @@ module.exports = class dsx extends Exchange {
'rateLimit': 1500,
'version': 'v3',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'createMarketOrder': false,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': false,
- 'fetchOrderBooks': false,
'createDepositAddress': true,
+ 'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': false,
'fetchDepositAddress': true,
- 'fetchTransactions': true,
- 'fetchTickers': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrderBooks': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTransactions': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/51840849/76909626-cb2bb100-68bc-11ea-99e0-28ba54f04792.jpg',
'api': {
- 'public': 'https://dsx.uk/mapi', // market data
- 'private': 'https://dsx.uk/tapi', // trading
- 'dwapi': 'https://dsx.uk/dwapi', // deposit/withdraw
+ 'public': 'https://dsxglobal.com/mapi', // market data
+ 'private': 'https://dsxglobal.com/tapi', // trading
+ 'dwapi': 'https://dsxglobal.com/dwapi', // deposit/withdraw
},
- 'www': 'https://dsx.uk',
+ 'www': 'https://dsxglobal.com',
'doc': [
- 'https://dsx.uk/developers/publicApi',
+ 'https://dsxglobal.com/developers/publicApi',
],
},
'fees': {
@@ -117,6 +124,7 @@ module.exports = class dsx extends Exchange {
'data unavailable': ExchangeNotAvailable,
'external service unavailable': ExchangeNotAvailable,
'nonce is invalid': InvalidNonce, // {"success":0,"error":"Parameter: nonce is invalid"}
+ 'Incorrect volume': InvalidOrder, // {"success": 0,"error":"Order was rejected. Incorrect volume."}
},
},
'options': {
@@ -539,7 +547,7 @@ module.exports = class dsx extends Exchange {
}
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -566,7 +574,7 @@ module.exports = class dsx extends Exchange {
return this.parseTrades (response[market['id']], market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// "high" : 0.01955,
@@ -714,9 +722,6 @@ module.exports = class dsx extends Exchange {
'filled': filled,
'fee': undefined,
// 'trades': this.parseTrades (order['trades'], market),
- 'clientOrderId': undefined,
- 'average': undefined,
- 'trades': undefined,
};
}
@@ -834,8 +839,10 @@ module.exports = class dsx extends Exchange {
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
'type': orderType,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'remaining': remaining,
@@ -843,7 +850,6 @@ module.exports = class dsx extends Exchange {
'status': status,
'fee': fee,
'trades': trades,
- 'average': undefined,
};
}
@@ -965,9 +971,6 @@ module.exports = class dsx extends Exchange {
'orderId': id,
};
const response = await this.privatePostOrderCancel (this.extend (request, params));
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- }
return response;
}
@@ -1188,7 +1191,7 @@ module.exports = class dsx extends Exchange {
body = this.urlencode (this.extend ({
'nonce': nonce,
}, query));
- const signature = this.decode (this.hmac (this.encode (body), this.encode (this.secret), 'sha512', 'base64'));
+ const signature = this.hmac (this.encode (body), this.encode (this.secret), 'sha512', 'base64');
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Key': this.apiKey,
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/eterbase.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/eterbase.js
new file mode 100644
index 000000000..56d975d44
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/eterbase.js
@@ -0,0 +1,1141 @@
+'use strict';
+
+// ----------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ArgumentsRequired, InvalidOrder, ExchangeError, BadRequest, BadSymbol } = require ('./base/errors');
+const { TRUNCATE, SIGNIFICANT_DIGITS } = require ('./base/functions/number');
+
+// ----------------------------------------------------------------------------
+
+module.exports = class eterbase extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'eterbase',
+ 'name': 'Eterbase',
+ 'countries': [ 'SK' ], // Slovakia
+ 'rateLimit': 500,
+ 'version': 'v1',
+ 'certified': true,
+ 'has': {
+ 'CORS': false,
+ 'publicAPI': true,
+ 'privateAPI': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'deposit': false,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': false,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
+ },
+ 'timeframes': {
+ '1m': '1',
+ '5m': '5',
+ '15m': '15',
+ '1h': '60',
+ '4h': '240',
+ '1d': '1440',
+ '1w': '10080',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/82067900-faeb0f80-96d9-11ea-9f22-0071cfcb9871.jpg',
+ 'api': 'https://api.eterbase.exchange',
+ 'www': 'https://www.eterbase.com',
+ 'doc': 'https://developers.eterbase.exchange',
+ 'fees': 'https://www.eterbase.com/exchange/fees',
+ 'referral': 'https://eterbase.exchange/invite/1wjjh4Pe',
+ },
+ 'api': {
+ 'markets': {
+ 'get': [
+ '{id}/order-book',
+ ],
+ },
+ 'public': {
+ 'get': [
+ 'ping',
+ 'assets',
+ 'markets',
+ 'tickers',
+ 'tickers/{id}/ticker',
+ 'markets/{id}/trades',
+ 'markets/{id}/ohlcv',
+ 'wstoken',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'accounts/{id}/balances',
+ 'accounts/{id}/orders',
+ 'accounts/{id}/fills',
+ 'orders/{id}/fills',
+ 'orders/{id}',
+ ],
+ 'post': [
+ 'orders',
+ 'accounts/{id}/withdrawals',
+ ],
+ 'delete': [
+ 'orders/{id}',
+ ],
+ },
+ 'feed': {
+ 'get': [
+ 'feed',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.35 / 100,
+ 'maker': 0.35 / 100,
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ 'uid': true,
+ },
+ 'precisionMode': SIGNIFICANT_DIGITS,
+ 'options': {
+ 'createMarketBuyOrderRequiresPrice': true,
+ },
+ 'exceptions': {
+ 'exact': {
+ 'Invalid cost': InvalidOrder, // {"message":"Invalid cost","_links":{"self":{"href":"/orders","templated":false}}}
+ 'Invalid order ID': InvalidOrder, // {"message":"Invalid order ID","_links":{"self":{"href":"/orders/4a151805-d594-4a96-9d64-e3984f2441f7","templated":false}}}
+ 'Invalid market !': BadSymbol, // {"message":"Invalid market !","_links":{"self":{"href":"/markets/300/order-book","templated":false}}}
+ },
+ 'broad': {
+ 'Failed to convert argument': BadRequest,
+ },
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetPing (params);
+ //
+ // { "pong": 1556354416582 }
+ //
+ return this.safeInteger (response, 'pong');
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetMarkets (params);
+ //
+ // [
+ // {
+ // "id":33,
+ // "symbol":"ETHUSDT",
+ // "base":"ETH",
+ // "quote":"USDT",
+ // "priceSigDigs":5,
+ // "qtySigDigs":8,
+ // "costSigDigs":8,
+ // "verificationLevelUser":1,
+ // "verificationLevelCorporate":11,
+ // "group":"USD",
+ // "tradingRules":[
+ // {"attribute":"Qty","condition":"Min","value":0.006},
+ // {"attribute":"Qty","condition":"Max","value":1000},
+ // {"attribute":"Cost","condition":"Min","value":1},
+ // {"attribute":"Cost","condition":"Max","value":210000}
+ // ],
+ // "allowedOrderTypes":[1,2,3,4],
+ // "state":"Trading"
+ // }
+ // ]
+ //
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const market = this.parseMarket (response[i]);
+ result.push (market);
+ }
+ return result;
+ }
+
+ parseMarket (market) {
+ //
+ // {
+ // "id":33,
+ // "symbol":"ETHUSDT",
+ // "base":"ETH",
+ // "quote":"USDT",
+ // "priceSigDigs":5,
+ // "qtySigDigs":8,
+ // "costSigDigs":8,
+ // "verificationLevelUser":1,
+ // "verificationLevelCorporate":11,
+ // "group":"USD",
+ // "tradingRules":[
+ // {"attribute":"Qty","condition":"Min","value":0.006},
+ // {"attribute":"Qty","condition":"Max","value":1000},
+ // {"attribute":"Cost","condition":"Min","value":1},
+ // {"attribute":"Cost","condition":"Max","value":210000}
+ // ],
+ // "allowedOrderTypes":[1,2,3,4],
+ // "state":"Trading"
+ // }
+ //
+ const id = this.safeString (market, 'id');
+ // const numericId = this.safeString (market, 'id');
+ const baseId = this.safeString (market, 'base');
+ const quoteId = this.safeString (market, 'quote');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const state = this.safeString (market, 'state');
+ const active = (state === 'Trading');
+ const precision = {
+ 'price': this.safeInteger (market, 'priceSigDigs'),
+ 'amount': this.safeInteger (market, 'qtySigDigs'),
+ 'cost': this.safeInteger (market, 'costSigDigs'),
+ };
+ const rules = this.safeValue (market, 'tradingRules', []);
+ let minAmount = undefined;
+ let maxAmount = undefined;
+ let minCost = undefined;
+ let maxCost = undefined;
+ for (let i = 0; i < rules.length; i++) {
+ const rule = rules[i];
+ const attribute = this.safeString (rule, 'attribute');
+ const condition = this.safeString (rule, 'condition');
+ const value = this.safeFloat (rule, 'value');
+ if ((attribute === 'Qty') && (condition === 'Min')) {
+ minAmount = value;
+ } else if ((attribute === 'Qty') && (condition === 'Max')) {
+ maxAmount = value;
+ } else if ((attribute === 'Cost') && (condition === 'Min')) {
+ minCost = value;
+ } else if ((attribute === 'Cost') && (condition === 'Max')) {
+ maxCost = value;
+ }
+ }
+ return {
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'info': market,
+ 'active': active,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': minAmount,
+ 'max': maxAmount,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': minCost,
+ 'max': maxCost,
+ },
+ },
+ };
+ }
+
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetAssets (params);
+ //
+ // [
+ // {
+ // "id":"LINK",
+ // "name":"ChainLink Token",
+ // "precisionDisplay":8,
+ // "precisionMax":18,
+ // "precisionBasis":1000000000000000000,
+ // "precisionStep":1,
+ // "verificationLevelMin":"null",
+ // "cmcId":"LINK",
+ // "txnUrl":"https://etherscan.io/tx/{txnId}",
+ // "state":"Active",
+ // "type":"Crypto",
+ // "isReference":false,
+ // "withdrawalMin":"0",
+ // "withdrawalMax":"50587",
+ // "withdrawalFee":"0.55",
+ // "depositEnabled":true,
+ // "withdrawalEnabled":true,
+ // "description":"",
+ // "coingeckoUrl":"https://www.coingecko.com/en/coins/chainlink",
+ // "coinmarketcapUrl":"https://coinmarketcap.com/currencies/chainlink",
+ // "eterbaseUrl":"https://www.eterbase.com/system-status/LINK",
+ // "explorerUrl":"https://etherscan.io/token/0x514910771af9ca656af840dff83e8264ecf986ca",
+ // "withdrawalMemoAllowed":false,
+ // "countries":[],
+ // "networks":[]
+ // }
+ // ]
+ //
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const currency = response[i];
+ const id = this.safeString (currency, 'id');
+ const precision = this.safeInteger (currency, 'precisionDisplay');
+ const code = this.safeCurrencyCode (id);
+ const depositEnabled = this.safeValue (currency, 'depositEnabled');
+ const withdrawalEnabled = this.safeValue (currency, 'withdrawalEnabled');
+ const state = this.safeString (currency, 'state');
+ const active = depositEnabled && withdrawalEnabled && (state === 'Active');
+ const type = this.safeStringLower (currency, 'type');
+ const name = this.safeString (currency, 'name');
+ result[code] = {
+ 'id': id,
+ 'info': currency,
+ 'code': code,
+ 'type': type,
+ 'name': name,
+ 'active': active,
+ 'fee': this.safeFloat (currency, 'withdrawalFee'),
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': Math.pow (10, -precision),
+ 'max': Math.pow (10, precision),
+ },
+ 'price': {
+ 'min': Math.pow (10, -precision),
+ 'max': Math.pow (10, precision),
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': this.safeFloat (currency, 'withdrawalMin'),
+ 'max': this.safeFloat (currency, 'withdrawalMax'),
+ },
+ },
+ };
+ }
+ return result;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker
+ //
+ // {
+ // "time":1588778516608,
+ // "marketId":250,
+ // "symbol": "ETHUSDT",
+ // "price":0.0,
+ // "change":0.0,
+ // "volumeBase":0.0,
+ // "volume":0.0,
+ // "low":0.0,
+ // "high":0.0,
+ // }
+ //
+ const marketId = this.safeString (ticker, 'marketId');
+ const symbol = this.safeSymbol (marketId, market);
+ const timestamp = this.safeInteger (ticker, 'time');
+ const last = this.safeFloat (ticker, 'price');
+ const baseVolume = this.safeFloat (ticker, 'volumeBase');
+ const quoteVolume = this.safeFloat (ticker, 'volume');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ const percentage = this.safeFloat (ticker, 'change');
+ const result = {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
+ 'bid': undefined,
+ 'bidVolume': undefined,
+ 'ask': undefined,
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': undefined,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined, // previous day close
+ 'change': undefined,
+ 'percentage': percentage,
+ 'average': undefined,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ return result;
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'id': market['id'],
+ };
+ const response = await this.publicGetTickersIdTicker (this.extend (request, params));
+ //
+ // {
+ // "time":1588778516608,
+ // "marketId":250,
+ // "price":0.0,
+ // "change":0.0,
+ // "volumeBase":0.0,
+ // "volume":0.0,
+ // "low":0.0,
+ // "high":0.0,
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ parseTickers (tickers, symbols = undefined) {
+ const result = [];
+ for (let i = 0; i < tickers.length; i++) {
+ result.push (this.parseTicker (tickers[i]));
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'quote': 'USDT', // identifier of a quote asset to filter the markets
+ };
+ const response = await this.publicGetTickers (this.extend (request, params));
+ //
+ // [
+ // {
+ // "time":1588831771698,
+ // "marketId":33,
+ // "price":204.54,
+ // "change":-1.03,
+ // "volumeBase":544.9801776699998,
+ // "volume":111550.433735,
+ // "low":200.33,
+ // "high":209.51
+ // },
+ // ]
+ //
+ return this.parseTickers (response, symbols);
+ }
+
+ parseTrade (trade, market) {
+ //
+ // fetchTrades (public)
+ //
+ // {
+ // "id":251199246,
+ // "side":2,
+ // "price":0.022044,
+ // "executedAt":1588830682664,
+ // "qty":0.13545846,
+ // "makerId":"67ed6ef3-33d8-4389-ba70-5c68d9db9f6c",
+ // "takerId":"229ef0d6-fe67-4b5d-9733-824142fab8f3"
+ // }
+ //
+ // fetchMyTrades, fetchOrderTrades (private)
+ //
+ // {
+ // "id": 123,
+ // "marketId": 123,
+ // "side": 1,
+ // "qty": "1.23456",
+ // "price": "1.23456",
+ // "cost": "1.23456",
+ // "fee": "1.23456",
+ // "feeAsset": "XBASE",
+ // "liquidity": 1,
+ // "orderId": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "tradeId": 123,
+ // "filledAt": 1556355722341
+ // }
+ //
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'qty');
+ let fee = undefined;
+ const feeCost = this.safeFloat (trade, 'fee');
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (trade, 'feeAsset');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': feeCost,
+ 'currency': feeCurrencyCode,
+ };
+ }
+ let cost = this.safeFloat (trade, 'qty');
+ if ((cost === undefined) && (price !== undefined) && (amount !== undefined)) {
+ cost = price * amount;
+ }
+ const timestamp = this.safeInteger2 (trade, 'executedAt', 'filledAt');
+ const tradeSide = this.safeString (trade, 'side');
+ const side = (tradeSide === '1') ? 'buy' : 'sell';
+ const liquidity = this.safeString (trade, 'liquidity');
+ let takerOrMaker = undefined;
+ if (liquidity !== undefined) {
+ takerOrMaker = (liquidity === '1') ? 'maker' : 'taker';
+ }
+ const orderId = this.safeString (trade, 'orderId');
+ const id = this.safeString (trade, 'id');
+ const marketId = this.safeString (trade, 'marketId');
+ const symbol = this.safeSymbol (marketId, market);
+ return {
+ 'info': trade,
+ 'id': id,
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'order': orderId,
+ 'type': undefined,
+ 'side': side,
+ 'takerOrMaker': takerOrMaker,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'id': market['id'],
+ // 'offset': 0 // the number of records to skip
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.publicGetMarketsIdTrades (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id":251199246,
+ // "side":2,
+ // "price":0.022044,
+ // "executedAt":1588830682664,
+ // "qty":0.13545846,
+ // "makerId":"67ed6ef3-33d8-4389-ba70-5c68d9db9f6c",
+ // "takerId":"229ef0d6-fe67-4b5d-9733-824142fab8f3"
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': this.marketId (symbol),
+ };
+ const response = await this.marketsGetIdOrderBook (this.extend (request, params));
+ //
+ // {
+ // "type":"ob_snapshot",
+ // "marketId":3,
+ // "timestamp":1588836429847,
+ // "bids":[
+ // [0.021694,8.8793688,1], // price, amount, count
+ // [0.01937,7.1340473,1],
+ // [0.020774,3.314881,1],
+ // ],
+ // "asks":[
+ // [0.02305,8.8793688,1],
+ // [0.028022,3.314881,1],
+ // [0.022598,3.314881,1],
+ // ]
+ // }
+ //
+ const timestamp = this.safeInteger (response, 'timestamp');
+ return this.parseOrderBook (response, timestamp);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "time":1588807500000,
+ // "open":0.022077,
+ // "high":0.022077,
+ // "low":0.022051,
+ // "close":0.022051,
+ // "volume":10.532025119999997
+ // }
+ //
+ return [
+ this.safeInteger (ohlcv, 'time'),
+ this.safeFloat (ohlcv, 'open'),
+ this.safeFloat (ohlcv, 'high'),
+ this.safeFloat (ohlcv, 'low'),
+ this.safeFloat (ohlcv, 'close'),
+ this.safeFloat (ohlcv, 'volume'),
+ ];
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ const request = {
+ // 'id': market['id'],
+ 'interval': this.timeframes[timeframe],
+ // 'start': 1588830682664, // milliseconds
+ // 'end': 1588830682664, // milliseconds
+ };
+ const duration = this.parseTimeframe (timeframe);
+ const now = this.milliseconds ();
+ if (since !== undefined) {
+ request['start'] = since;
+ if (limit === undefined) {
+ request['end'] = now;
+ } else {
+ request['end'] = this.sum (since, duration * limit * 1000);
+ }
+ } else if (limit !== undefined) {
+ request['start'] = now - duration * limit * 1000;
+ request['end'] = now;
+ } else {
+ throw new ArgumentsRequired (this.id + ' fetchOHLCV requires a since argument, or a limit argument, or both');
+ }
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ request['id'] = market['id'];
+ const response = await this.publicGetMarketsIdOhlcv (this.extend (request, params));
+ //
+ // [
+ // {"time":1588807500000,"open":0.022077,"high":0.022077,"low":0.022051,"close":0.022051,"volume":10.532025119999997},
+ // {"time":1588807800000,"open":0.022051,"high":0.022051,"low":0.022044,"close":0.022044,"volume":0.655987},
+ // {"time":1588808400000,"open":0.022044,"high":0.022044,"low":0.022044,"close":0.022044,"volume":3.9615545499999993},
+ // ]
+ //
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': this.uid,
+ };
+ const response = await this.privateGetAccountsIdBalances (this.extend (request, params));
+ //
+ // [
+ // {
+ // "assetId":"USDT",
+ // "available":"25",
+ // "balance":"25",
+ // "reserved":"0",
+ // "balanceBtc":"0.0",
+ // "balanceRef":"0.0",
+ // }
+ // ]
+ //
+ const result = { 'info': response };
+ for (let i = 0; i < response.length; i++) {
+ const balance = response[i];
+ const currencyId = this.safeString (balance, 'assetId');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = {
+ 'free': this.safeFloat (balance, 'available'),
+ 'used': this.safeFloat (balance, 'reserved'),
+ 'total': this.safeFloat (balance, 'balance'),
+ };
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const response = await this.privateGetOrdersId (this.extend (request, params));
+ //
+ // {
+ // "id": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "accountId": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "marketId": 123,
+ // "type": 1,
+ // "side": 1,
+ // "qty": "1.23456",
+ // "cost": "1.23456",
+ // "remainingQty": "1.23456",
+ // "remainingCost": "1.23456",
+ // "limitPrice": "1.23456",
+ // "stopPrice": "1.23456",
+ // "postOnly": false,
+ // "timeInForce": "GTC",
+ // "state": 1,
+ // "closeReason": "FILLED",
+ // "placedAt": 1556355722341,
+ // "closedAt": 1556355722341
+ // }
+ //
+ return this.parseOrder (response);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ '1': undefined, // pending
+ '2': 'open', // open
+ '3': 'open', // partially filled
+ '4': 'closed', // closed
+ 'FILLED': 'closed',
+ 'USER_REQUESTED_CANCEL': 'canceled',
+ 'ADMINISTRATIVE_CANCEL': 'canceled',
+ 'NOT_ENOUGH_LIQUIDITY': 'canceled',
+ 'EXPIRED': 'expired',
+ 'ONE_CANCELS_OTHER': 'canceled',
+ };
+ return this.safeString (statuses, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // fetchOrder, fetchOpenOrders, fetchClosedOrders
+ //
+ // {
+ // "id": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "accountId": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "marketId": 123,
+ // "type": 1,
+ // "side": 1,
+ // "qty": "1.23456",
+ // "cost": "1.23456",
+ // "remainingQty": "1.23456",
+ // "remainingCost": "1.23456",
+ // "limitPrice": "1.23456",
+ // "stopPrice": "1.23456",
+ // "postOnly": false,
+ // "timeInForce": "GTC",
+ // "state": 1,
+ // "closeReason": "FILLED",
+ // "placedAt": 1556355722341,
+ // "closedAt": 1556355722341
+ // }
+ //
+ // createOrder
+ //
+ // market buy
+ //
+ // {
+ // "id":"ff81127c-8fd5-4846-b683-110639dcd322",
+ // "accountId":"6d445378-d8a3-4932-91cd-545d0a4ad2a2",
+ // "marketId":33,
+ // "type":1,
+ // "side":1,
+ // "cost":"25",
+ // "postOnly":false,
+ // "timeInForce":"GTC",
+ // "state":1,
+ // "placedAt":1589510846735
+ // }
+ //
+ // market sell, limit buy, limit sell
+ //
+ // {
+ // "id":"042a38b0-e369-4ad2-ae73-a18ff6b1dcf1",
+ // "accountId":"6d445378-d8a3-4932-91cd-545d0a4ad2a2",
+ // "marketId":33,
+ // "type":2,
+ // "side":1,
+ // "qty":"1000",
+ // "limitPrice":"100",
+ // "postOnly":false,
+ // "timeInForce":"GTC",
+ // "state":1,
+ // "placedAt":1589403938682,
+ // }
+ //
+ const id = this.safeString (order, 'id');
+ const timestamp = this.safeInteger (order, 'placedAt');
+ const marketId = this.safeInteger (order, 'marketId');
+ const symbol = this.safeSymbol (marketId, market);
+ let status = this.parseOrderStatus (this.safeString (order, 'state'));
+ if (status === 'closed') {
+ status = this.parseOrderStatus (this.safeString (order, 'closeReason'));
+ }
+ const orderSide = this.safeString (order, 'side');
+ const side = (orderSide === '1') ? 'buy' : 'sell';
+ const orderType = this.safeString (order, 'type');
+ let type = undefined;
+ if (orderType === '1') {
+ type = 'market';
+ } else if (orderType === '2') {
+ type = 'limit';
+ } else if (orderType === '3') {
+ type = 'stopmarket';
+ } else {
+ type = 'stoplimit';
+ }
+ let price = this.safeFloat (order, 'limitPrice');
+ const amount = this.safeFloat (order, 'qty');
+ let remaining = this.safeFloat (order, 'remainingQty');
+ let filled = undefined;
+ const remainingCost = this.safeFloat (order, 'remainingCost');
+ if ((remainingCost !== undefined) && (remainingCost === 0.0)) {
+ remaining = 0;
+ }
+ if ((amount !== undefined) && (remaining !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ const cost = this.safeFloat (order, 'cost');
+ if (type === 'market') {
+ if (price === 0.0) {
+ if ((cost !== undefined) && (filled !== undefined)) {
+ if ((cost > 0) && (filled > 0)) {
+ price = cost / filled;
+ }
+ }
+ }
+ }
+ let average = undefined;
+ if (cost !== undefined) {
+ if (filled) {
+ average = cost / filled;
+ }
+ }
+ const timeInForce = this.safeString (order, 'timeInForce');
+ const stopPrice = this.safeFloat (order, 'stopPrice');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'side': side,
+ 'timeInForce': timeInForce,
+ 'price': price,
+ 'stopPrice': stopPrice,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': undefined,
+ 'trades': undefined,
+ };
+ }
+
+ async fetchOrdersByState (state, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const now = this.milliseconds ();
+ const ninetyDays = 90 * 24 * 60 * 60 * 1000; // 90 days timerange max
+ const request = {
+ 'id': this.uid,
+ 'state': state,
+ // 'side': Integer, // 1 = buy, 2 = sell
+ // 'offset': 0, // the number of records to skip
+ };
+ if (since === undefined) {
+ request['from'] = now - ninetyDays;
+ request['to'] = now;
+ } else {
+ request['from'] = since;
+ request['to'] = this.sum (since, ninetyDays);
+ }
+ await this.loadMarkets ();
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['marketId'] = market['id'];
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 50
+ }
+ const response = await this.privateGetAccountsIdOrders (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "accountId": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "marketId": 123,
+ // "type": 1,
+ // "side": 1,
+ // "qty": "1.23456",
+ // "cost": "1.23456",
+ // "remainingQty": "1.23456",
+ // "remainingCost": "1.23456",
+ // "limitPrice": "1.23456",
+ // "stopPrice": "1.23456",
+ // "postOnly": false,
+ // "timeInForce": "GTC",
+ // "state": 1,
+ // "closeReason": "FILLED",
+ // "placedAt": 1556355722341,
+ // "closedAt": 1556355722341
+ // }
+ // ]
+ //
+ return this.parseOrders (response, market, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchOrdersByState ('INACTIVE', symbol, since, limit, params);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ return await this.fetchOrdersByState ('ACTIVE', symbol, since, limit, params);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const now = this.milliseconds ();
+ const ninetyDays = 90 * 24 * 60 * 60 * 1000; // 90 days timerange max
+ const request = {
+ 'id': this.uid,
+ // 'side': Integer, // 1 = buy, 2 = sell
+ // 'offset': 0, // the number of records to skip
+ };
+ if (since === undefined) {
+ request['from'] = now - ninetyDays;
+ request['to'] = now;
+ } else {
+ request['from'] = since;
+ request['to'] = this.sum (since, ninetyDays);
+ }
+ await this.loadMarkets ();
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['marketId'] = market['id'];
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 50, max 200
+ }
+ const response = await this.privateGetAccountsIdFills (this.extend (request, params));
+ //
+ // [
+ // {
+ // "id": 123,
+ // "marketId": 123,
+ // "side": 1,
+ // "qty": "1.23456",
+ // "price": "1.23456",
+ // "cost": "1.23456",
+ // "fee": "1.23456",
+ // "feeAsset": "XBASE",
+ // "liquidity": 1,
+ // "orderId": "30a2b5d0-be2e-4d0a-93ed-a7c45fed1792",
+ // "tradeId": 123,
+ // "filledAt": 1556355722341
+ // }
+ // ]
+ //
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const trades = await this.privateGetOrdersIdFills (this.extend (request, params));
+ return this.parseTrades (trades);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const uppercaseType = type.toUpperCase ();
+ if (uppercaseType === 'MARKET') {
+ type = 1;
+ } else if (uppercaseType === 'LIMIT') {
+ type = 2;
+ } else if (uppercaseType === 'STOPMARKET') {
+ type = 3;
+ } else if (uppercaseType === 'STOPLIMIT') {
+ type = 4;
+ }
+ const uppercaseSide = side.toUpperCase ();
+ side = uppercaseSide === 'BUY' ? 1 : 2;
+ const request = {
+ 'accountId': this.uid,
+ 'marketId': market['id'],
+ 'type': type,
+ 'side': side,
+ // 'postOnly': false,
+ // 'timeInForce': 'GTC',
+ };
+ const clientOrderId = this.safeValue2 (params, 'refId', 'clientOrderId');
+ let query = params;
+ if (clientOrderId !== undefined) {
+ request['refId'] = clientOrderId;
+ query = this.omit (params, [ 'refId', 'clientOrderId' ]);
+ }
+ if ((uppercaseType === 'MARKET') && (uppercaseSide === 'BUY')) {
+ // for market buy it requires the amount of quote currency to spend
+ let cost = this.safeFloat (params, 'cost');
+ if (this.options['createMarketBuyOrderRequiresPrice']) {
+ if (cost === undefined) {
+ if (price !== undefined) {
+ cost = amount * price;
+ } else {
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false to supply the cost in the amount argument (the exchange-specific behaviour)");
+ }
+ }
+ } else {
+ cost = (cost === undefined) ? amount : cost;
+ }
+ const precision = market['precision']['price'];
+ request['cost'] = this.decimalToPrecision (cost, TRUNCATE, precision, this.precisionMode);
+ } else {
+ request['qty'] = this.amountToPrecision (symbol, amount);
+ }
+ if (uppercaseType === 'LIMIT') {
+ request['limitPrice'] = this.priceToPrecision (symbol, price);
+ }
+ const response = await this.privatePostOrders (this.extend (request, query));
+ //
+ // market buy
+ //
+ // {
+ // "id":"ff81127c-8fd5-4846-b683-110639dcd322",
+ // "accountId":"6d445378-d8a3-4932-91cd-545d0a4ad2a2",
+ // "marketId":33,
+ // "type":1,
+ // "side":1,
+ // "cost":"25",
+ // "postOnly":false,
+ // "timeInForce":"GTC",
+ // "state":1,
+ // "placedAt":1589510846735
+ // }
+ //
+ // market sell, limit buy, limit sell
+ //
+ // {
+ // "id":"042a38b0-e369-4ad2-ae73-a18ff6b1dcf1",
+ // "accountId":"6d445378-d8a3-4932-91cd-545d0a4ad2a2",
+ // "marketId":33,
+ // "type":2,
+ // "side":1,
+ // "qty":"1000",
+ // "limitPrice":"100",
+ // "postOnly":false,
+ // "timeInForce":"GTC",
+ // "state":1,
+ // "placedAt":1589403938682,
+ // }
+ //
+ return this.parseOrder (response, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ const request = {
+ 'id': id,
+ };
+ return await this.privateDeleteOrdersId (this.extend (request, params));
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkAddress (address);
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'id': this.uid,
+ 'accountId': this.uid,
+ 'assetId': currency['id'],
+ 'amount': amount,
+ // 'cryptoAddress': address,
+ // 'accountNumber': 'IBAN', // IBAN account number
+ // 'networkId': 'XBASE', // underlying network
+ };
+ if (address !== undefined) {
+ request['cryptoAddress'] = address;
+ if (tag !== undefined) {
+ request['memo'] = tag;
+ }
+ }
+ const response = await this.privatePostAccountsIdWithdrawals (this.extend (request, params));
+ //
+ // {
+ // "id": "98b62dde-a87f-45f0-8db8-80ae2d312fa6"
+ // }
+ //
+ return {
+ 'info': response,
+ 'id': this.safeString (response, 'id'),
+ };
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, httpHeaders = undefined, body = undefined) {
+ const query = this.omit (params, this.extractParams (path));
+ let request = '/';
+ if (api === 'public') {
+ request += 'api/' + this.version;
+ } else if (api === 'private') {
+ request += 'api/' + this.version;
+ } else if (api === 'markets') {
+ request += 'api/' + api;
+ }
+ request += '/' + this.implodeParams (path, params);
+ if (method === 'GET') {
+ if (Object.keys (query).length) {
+ request += '?' + this.urlencode (query);
+ }
+ }
+ const url = this.urls['api'] + request;
+ if (api === 'private') {
+ this.checkRequiredCredentials ();
+ let payload = '';
+ if (method !== 'GET') {
+ if (Object.keys (query).length) {
+ body = this.json (query);
+ payload = body;
+ }
+ }
+ // construct signature
+ const hasBody = (method === 'POST') || (method === 'PUT') || (method === 'PATCH');
+ // const date = 'Mon, 30 Sep 2019 13:57:23 GMT';
+ const date = this.rfc2616 (this.milliseconds ());
+ let headersCSV = 'date' + ' ' + 'request-line';
+ let message = 'date' + ':' + ' ' + date + "\n" + method + ' ' + request + ' HTTP/1.1'; // eslint-disable-line quotes
+ let digest = '';
+ if (hasBody) {
+ digest = 'SHA-256=' + this.hash (payload, 'sha256', 'base64');
+ message += "\ndigest" + ':' + ' ' + digest; // eslint-disable-line quotes
+ headersCSV += ' ' + 'digest';
+ }
+ const signature = this.hmac (this.encode (message), this.encode (this.secret), 'sha256', 'base64');
+ const authorizationHeader = 'hmac username="' + this.apiKey + '",algorithm="hmac-sha256",headers="' + headersCSV + '",' + 'signature="' + signature + '"';
+ httpHeaders = {
+ 'Date': date,
+ 'Authorization': authorizationHeader,
+ 'Content-Type': 'application/json',
+ };
+ if (hasBody) {
+ httpHeaders['Digest'] = digest;
+ }
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': httpHeaders };
+ }
+
+ handleErrors (httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return; // fallback to default error handler
+ }
+ //
+ // {"message":"Invalid cost","_links":{"self":{"href":"/orders","templated":false}}}
+ //
+ const message = this.safeString (response, 'message');
+ if (message !== undefined) {
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/exmo.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/exmo.js
similarity index 83%
rename from TaskServer/node_modules/ccxt/js/exmo.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/exmo.js
index 6cc36522d..52c2ba65e 100644
--- a/TaskServer/node_modules/ccxt/js/exmo.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/exmo.js
@@ -16,23 +16,28 @@ module.exports = class exmo extends Exchange {
'rateLimit': 350, // once every 350 ms ≈ 180 requests per minute ≈ 3 requests per second
'version': 'v1.1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchClosedOrders': 'emulated',
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchCurrencies': true,
'fetchDepositAddress': true,
+ 'fetchFundingFees': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
'fetchOpenOrders': true,
'fetchOrder': 'emulated',
- 'fetchOrders': 'emulated',
- 'fetchOrderTrades': true,
+ 'fetchOrderBook': true,
'fetchOrderBooks': true,
- 'fetchMyTrades': true,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
'fetchTickers': true,
- 'withdraw': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
- 'fetchFundingFees': true,
- 'fetchCurrencies': true,
'fetchTransactions': true,
- 'fetchOHLCV': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1',
@@ -73,11 +78,14 @@ module.exports = class exmo extends Exchange {
'public': {
'get': [
'currency',
+ 'currency/list/extended',
'order_book',
'pair_settings',
'ticker',
'trades',
'candles_history',
+ 'required_amount',
+ 'payments/providers/crypto/list',
],
},
'private': {
@@ -91,13 +99,14 @@ module.exports = class exmo extends Exchange {
'user_trades',
'user_cancelled_orders',
'order_trades',
- 'required_amount',
'deposit_address',
'withdraw_crypt',
'withdraw_get_txid',
'excode_create',
'excode_load',
+ 'code_check',
'wallet_history',
+ 'wallet_operations',
],
},
},
@@ -121,229 +130,210 @@ module.exports = class exmo extends Exchange {
'error': '',
'data': {
'limits': [
- { 'pair': 'ALGO/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' },
- { 'pair': 'ALGO/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '50' },
- { 'pair': 'ATOM/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '50000000' },
- { 'pair': 'ATOM/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'BTC/USD', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'BTC/RUB', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'BTC/EUR', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'BTC/UAH', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '15000000', 'min_a': '10', 'max_a': '15000000' },
- { 'pair': 'BTC/GBP', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'ETH/GBP', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'XRP/GBP', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
- { 'pair': 'USDT/GBP', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'BTC/PLN', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '20000000', 'min_a': '50', 'max_a': '2000000' },
- { 'pair': 'BTC/TRY', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000' },
- { 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000' },
- { 'pair': 'BTC/USDT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'ETH/BTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ETH/USD', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'ETH/RUB', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
- { 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
- { 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000' },
- { 'pair': 'ADA/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' },
- { 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'ALGO/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'ALGO/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' },
- { 'pair': 'ALGO/EUR', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'ATOM/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'ATOM/EUR', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000' },
- { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000' },
- { 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' },
- { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000' },
- { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'BTCZ/BTC', 'min_q': '100', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000' },
- { 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' },
- { 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100' },
- { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' },
- { 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
- { 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
- { 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000' },
- { 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000' },
- { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
- { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000' },
- { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000' },
- { 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000' },
- { 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'DXT/USD', 'min_q': '100', 'max_q': '50000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'DXT/BTC', 'min_q': '100', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000' },
- { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ETH/EUR', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'ETH/UAH', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000' },
- { 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '2000000' },
- { 'pair': 'ETH/TRY', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000' },
- { 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'ETH/USDT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'ETH/LTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '100000', 'min_a': '0.05', 'max_a': '100000' },
- { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10' },
- { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000' },
- { 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
- { 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' },
- { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'GNT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
- { 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'GUSD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'GUSD/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' },
- { 'pair': 'HP/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'HB/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' },
- { 'pair': 'INK/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'INK/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'INK/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000' },
- { 'pair': 'KICK/RUB', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'KICK/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000' },
- { 'pair': 'KICK/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'KICK/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000' },
- { 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000' },
- { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100' },
- { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000' },
- { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000' },
- { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'MKR/BTC', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100' },
- { 'pair': 'MKR/DAI', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000' },
- { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' },
- { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100' },
- { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000' },
- { 'pair': 'MNX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'MNX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'MNX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
- { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000' },
- { 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
- { 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000' },
- { 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
- { 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000' },
- { 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000' },
- { 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000' },
- { 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
- { 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000' },
- { 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000' },
- { 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000' },
- { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' },
- { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000' },
- { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000' },
- { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' },
- { 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000' },
- { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'TRX/EUR', 'min_q': '0.01', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
- { 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
- { 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000' },
- { 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000' },
- { 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000' },
- { 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000' },
- { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100' },
- { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500' },
- { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000' },
- { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100' },
- { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000' },
- { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
- { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000' },
- { 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000' },
- { 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000' },
- { 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000' },
- { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
- { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000' },
- { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000' },
- { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000' },
- { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000' },
- { 'pair': 'XTZ/USD', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000' },
- { 'pair': 'XTZ/RUB', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '500000' },
- { 'pair': 'XTZ/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10' },
- { 'pair': 'XTZ/ETH', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '1000' },
- { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000' },
- { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000' },
- { 'pair': 'ZRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100' },
- { 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000' },
- { 'pair': 'ZAG/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100' },
- { 'pair': 'USD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000' },
- { 'pair': 'EXM/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0000001', 'max_a': '1' },
- { 'pair': 'ATMCASH/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10' },
+ { 'pair': 'BTC/USD', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/RUB', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '2000000', 'min_a': '10', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/EUR', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/GBP', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '30000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/UAH', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '15000000', 'min_a': '10', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/PLN', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '20000000', 'min_a': '50', 'max_a': '2000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/TRY', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1', 'max_p': '800000', 'min_a': '40', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/KZT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '1000', 'max_p': '12000000', 'min_a': '1000', 'max_a': '100000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTC/USDT', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.01', 'max_p': '30000', 'min_a': '3', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'ETH/BTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/USD', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/RUB', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/USD', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/RUB', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ADA/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ADA/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ADA/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ALGO/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ALGO/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '50', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ALGO/USDT', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'ALGO/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ALGO/EUR', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ATOM/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ATOM/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ATOM/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ATOM/EUR', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/USD', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '30000', 'min_a': '0.0001', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/RUB', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '2000000', 'min_a': '0.0001', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/EUR', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/UAH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.1', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/BTC', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '5', 'min_a': '0.0001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/ETH', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.0000001', 'max_p': '200', 'min_a': '0.0001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BCH/USDT', 'min_q': '0.003', 'max_q': '5000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'BTG/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTG/BTC', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTG/ETH', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.01', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTT/RUB', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTT/UAH', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.000001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'BTT/BTC', 'min_q': '1', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'CRON/BTC', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'CRON/ETH', 'min_q': '1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'CRON/USDT', 'min_q': '1', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'CRON/EXM', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DAI/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DAI/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '0.5', 'max_a': '30000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DAI/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DAI/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DASH/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DASH/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DASH/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '200000', 'min_a': '10', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DASH/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DASH/USDT', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.01', 'max_p': '5000', 'min_a': '3', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'DCR/RUB', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '3000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DCR/UAH', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.25', 'max_a': '1000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DCR/BTC', 'min_q': '0.01', 'max_q': '50000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DOGE/USD', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'DOGE/BTC', 'min_q': '100', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'EOS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'EOS/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'EOS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETC/USD', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETC/RUB', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '0.01', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETC/BTC', 'min_q': '0.2', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '0.5', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/EUR', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/GBP', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/UAH', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '1000000', 'min_a': '90', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/PLN', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '2000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/TRY', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.1', 'max_p': '80000', 'min_a': '10', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/KZT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '4', 'max_p': '40000000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETH/USDT', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '3', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'ETH/LTC', 'min_q': '0.001', 'max_q': '5000', 'min_p': '0.00000001', 'max_p': '100000', 'min_a': '0.05', 'max_a': '100000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETZ/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '10', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETZ/ETH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ETZ/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '1000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'EXM/USDT', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '100000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'EXM/ETH', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GAS/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GAS/BTC', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GNT/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GNT/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GUSD/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GUSD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'GUSD/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'HP/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'HB/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LSK/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.1', 'max_p': '1000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LSK/RUB', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LSK/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.0015', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LTC/USD', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LTC/RUB', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '150', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LTC/EUR', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LTC/UAH', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.01', 'max_p': '300000', 'min_a': '5', 'max_a': '18000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'LTC/BTC', 'min_q': '0.05', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'MKR/BTC', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.0001', 'max_p': '100', 'min_a': '0.000001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'MKR/DAI', 'min_q': '0.0001', 'max_q': '1000', 'min_p': '0.5', 'max_p': '500000', 'min_a': '0.005', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'MNC/USD', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'MNC/BTC', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'MNC/ETH', 'min_q': '10', 'max_q': '500000000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '1000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'NEO/USD', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.01', 'max_p': '50000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'NEO/RUB', 'min_q': '0.01', 'max_q': '100000', 'min_p': '0.001', 'max_p': '1500000', 'min_a': '50', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'NEO/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'OMG/USD', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'OMG/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'OMG/ETH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONG/EXM', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONG/BTC', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONG/RUB', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '250000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONG/UAH', 'min_q': '1', 'max_q': '1000000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '50', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONT/EXM', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONT/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '100', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ONT/UAH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '100000', 'min_a': '200', 'max_a': '250000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'PTI/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '600000', 'min_a': '10', 'max_a': '600000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'PTI/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.000001', 'max_a': '10', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'PTI/EOS', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0000001', 'max_p': '5000', 'min_a': '0.01', 'max_a': '20000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'PTI/USDT', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '10000', 'min_a': '0.01', 'max_a': '100000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'QTUM/USD', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '10000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'QTUM/BTC', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'QTUM/ETH', 'min_q': '0.1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ROOBEE/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'SMART/USD', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'SMART/RUB', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.0001', 'max_p': '100000', 'min_a': '10', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'SMART/EUR', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.000001', 'max_p': '1000', 'min_a': '1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'SMART/BTC', 'min_q': '10', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'TRX/USD', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'TRX/EUR', 'min_q': '0.01', 'max_q': '50000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'TRX/RUB', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'TRX/UAH', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.000001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'TRX/BTC', 'min_q': '1', 'max_q': '50000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDC/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDC/BTC', 'min_q': '1', 'max_q': '500000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDC/ETH', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '1000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDC/USDT', 'min_q': '1', 'max_q': '500000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '3', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'USDT/USD', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDT/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDT/EUR', 'min_q': '0.01', 'max_q': '500000', 'min_p': '0.1', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDT/GBP', 'min_q': '1', 'max_q': '500000', 'min_p': '0.5', 'max_p': '10', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDT/UAH', 'min_q': '0.01', 'max_q': '500000', 'min_p': '1', 'max_p': '3000', 'min_a': '2', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USDT/KZT', 'min_q': '1', 'max_q': '500000', 'min_p': '200', 'max_p': '4000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'VLX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'WAVES/USD', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.001', 'max_p': '3500', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'WAVES/RUB', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.01', 'max_p': '10000', 'min_a': '1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'WAVES/BTC', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.000001', 'max_p': '1', 'min_a': '0.0001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'WAVES/ETH', 'min_q': '0.5', 'max_q': '500000', 'min_p': '0.00001', 'max_p': '30', 'min_a': '0.0035', 'max_a': '3500', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XEM/USD', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XEM/EUR', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XEM/UAH', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.0001', 'max_p': '30000', 'min_a': '10', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XEM/BTC', 'min_q': '10', 'max_q': '10000000', 'min_p': '0.0000001', 'max_p': '1', 'min_a': '0.00015', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XLM/USD', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XLM/RUB', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XLM/TRY', 'min_q': '0.01', 'max_q': '5000000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XLM/BTC', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '600000', 'min_a': '10', 'max_a': '16000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/UAH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '300000', 'min_a': '5', 'max_a': '16000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.0001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XMR/ETH', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00000001', 'max_p': '100', 'min_a': '0.001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/EUR', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/GBP', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/TRY', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '6000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/UAH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.01', 'max_a': '15000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XRP/USDT', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.001', 'max_p': '1000', 'min_a': '0.001', 'max_a': '500000', 'taker': '0', 'maker': '0' },
+ { 'pair': 'XRP/ETH', 'min_q': '1', 'max_q': '5000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.00001', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XTZ/USD', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '100000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XTZ/RUB', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00001', 'max_p': '100000', 'min_a': '0.5', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XTZ/BTC', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.00001', 'max_a': '10', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'XTZ/ETH', 'min_q': '0.1', 'max_q': '100000', 'min_p': '0.0000001', 'max_p': '10', 'min_a': '0.0001', 'max_a': '1000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZEC/USD', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZEC/RUB', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '100000', 'min_a': '0.1', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZEC/EUR', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.001', 'max_p': '5000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZEC/BTC', 'min_q': '0.01', 'max_q': '10000', 'min_p': '0.00001', 'max_p': '10', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZRX/USD', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00001', 'max_p': '1000', 'min_a': '0.1', 'max_a': '500000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZRX/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZRX/ETH', 'min_q': '0.01', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '10', 'min_a': '0.01', 'max_a': '5000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'ZAG/BTC', 'min_q': '1', 'max_q': '10000000', 'min_p': '0.00000001', 'max_p': '0.1', 'min_a': '0.00001', 'max_a': '100', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'USD/RUB', 'min_q': '1', 'max_q': '500000', 'min_p': '0.01', 'max_p': '1000', 'min_a': '10', 'max_a': '50000000', 'taker': '0.4', 'maker': '0.4' },
+ { 'pair': 'EXM/BTC', 'min_q': '1', 'max_q': '100000000', 'min_p': '0.00000001', 'max_p': '1', 'min_a': '0.0000001', 'max_a': '1', 'taker': '0.4', 'maker': '0.4' },
],
'fees': [
{
'group': 'crypto',
- 'title': 'Криптовалюта',
+ 'title': 'Cryptocurrency',
'items': [
{ 'prov': 'EXM', 'dep': '0%', 'wd': '1 EXM' },
- { 'prov': 'BTC', 'dep': '0%', 'wd': '0.0005 BTC' },
+ { 'prov': 'BTC', 'dep': '0%', 'wd': '0.0004 BTC' },
{ 'prov': 'LTC', 'dep': '0%', 'wd': '0.01 LTC' },
- { 'prov': 'DOGE', 'dep': '0%', 'wd': '1 DOGE' },
- { 'prov': 'DASH', 'dep': '0%', 'wd': '0.01 DASH' },
- { 'prov': 'ETH', 'dep': '0%', 'wd': '0.01 ETH' },
+ { 'prov': 'DOGE', 'dep': '0%', 'wd': '1 Doge' },
+ { 'prov': 'DASH', 'dep': '0%', 'wd': '0.002 DASH' },
+ { 'prov': 'ETH', 'dep': '0%', 'wd': '0.003 ETH' },
{ 'prov': 'WAVES', 'dep': '0%', 'wd': '0.001 WAVES' },
{ 'prov': 'ZEC', 'dep': '0%', 'wd': '0.001 ZEC' },
- { 'prov': 'USDT', 'dep': '0%', 'wd': '5 USDT' },
- { 'prov': 'XMR', 'dep': '0%', 'wd': '0.05 XMR' },
+ { 'prov': 'USDT', 'dep': '0%', 'wd': '' },
+ { 'prov': 'XMR', 'dep': '0%', 'wd': '0.001 XMR' },
{ 'prov': 'XRP', 'dep': '0%', 'wd': '0.02 XRP' },
- { 'prov': 'KICK', 'dep': '0%', 'wd': '50 KICK' },
{ 'prov': 'ETC', 'dep': '0%', 'wd': '0.01 ETC' },
{ 'prov': 'BCH', 'dep': '0%', 'wd': '0.001 BCH' },
{ 'prov': 'BTG', 'dep': '0%', 'wd': '0.001 BTG' },
{ 'prov': 'EOS', 'dep': '0%', 'wd': '0.05 EOS' },
- { 'prov': 'BTCZ', 'dep': '0%', 'wd': '5 BTCZ' },
- { 'prov': 'DXT', 'dep': '20 DXT', 'wd': '20 DXT' },
{ 'prov': 'XLM', 'dep': '0%', 'wd': '0.01 XLM' },
- { 'prov': 'MNX', 'dep': '0%', 'wd': '0.01 MNX' },
{ 'prov': 'OMG', 'dep': '0.1 OMG', 'wd': '0.5 OMG' },
{ 'prov': 'TRX', 'dep': '0%', 'wd': '1 TRX' },
{ 'prov': 'ADA', 'dep': '0%', 'wd': '1 ADA' },
- { 'prov': 'INK', 'dep': '10 INK', 'wd': '50 INK' },
{ 'prov': 'NEO', 'dep': '0%', 'wd': '0%' },
{ 'prov': 'GAS', 'dep': '0%', 'wd': '0%' },
{ 'prov': 'ZRX', 'dep': '0%', 'wd': '1 ZRX' },
@@ -357,29 +347,28 @@ module.exports = class exmo extends Exchange {
{ 'prov': 'DAI', 'dep': '0%', 'wd': '1 DAI' },
{ 'prov': 'MKR', 'dep': '0%', 'wd': '0.005 MKR' },
{ 'prov': 'MNC', 'dep': '0%', 'wd': '15 MNC' },
- { 'prov': 'PTI', 'dep': '0%', 'wd': '10 PTI' },
- { 'prov': 'ATMCASH', 'dep': '0%', 'wd': '5 ATMCASH' },
+ { 'prov': 'PTI', 'dep': '-', 'wd': '10 PTI' },
{ 'prov': 'ETZ', 'dep': '0%', 'wd': '1 ETZ' },
{ 'prov': 'USDC', 'dep': '0%', 'wd': '0.5 USDC' },
{ 'prov': 'ROOBEE', 'dep': '0%', 'wd': '200 ROOBEE' },
{ 'prov': 'DCR', 'dep': '0%', 'wd': '0.01 DCR' },
{ 'prov': 'ZAG', 'dep': '0%', 'wd': '0%' },
- { 'prov': 'BTT', 'dep': '0%', 'wd': '100 BTT' },
+ { 'prov': 'BTT', 'dep': '0 BTT', 'wd': '100 BTT' },
{ 'prov': 'VLX', 'dep': '0%', 'wd': '1 VLX' },
{ 'prov': 'CRON', 'dep': '0%', 'wd': '5 CRON' },
{ 'prov': 'ONT', 'dep': '0%', 'wd': '1 ONT' },
{ 'prov': 'ONG', 'dep': '0%', 'wd': '5 ONG' },
{ 'prov': 'ALGO', 'dep': '0%', 'wd': '0.01 ALGO' },
- { 'prov': 'ATOM', 'dep': '0%', 'wd': '' },
+ { 'prov': 'ATOM', 'dep': '0%', 'wd': '0.05 ATOM' },
],
},
{
'group': 'usd',
'title': 'USD',
'items': [
- { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Payeer', 'dep': '3.95%', 'wd': '-' },
- { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.49%' },
+ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
+ { 'prov': 'AdvCash', 'dep': '0%', 'wd': '2.49%' },
{ 'prov': 'Visa/MasterCard (Simplex)', 'dep': '4.5% + 0.5 USD', 'wd': '-' },
{ 'prov': 'Visa', 'dep': '3.45%', 'wd': '-' },
{ 'prov': 'Frick Bank', 'dep': '0 USD', 'wd': '-' },
@@ -389,24 +378,32 @@ module.exports = class exmo extends Exchange {
'group': 'eur',
'title': 'EUR',
'items': [
+ { 'prov': 'Visa/MasterCard', 'dep': '4.5% + 0.5 EUR', 'wd': '-' },
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
- { 'prov': 'Visa/MasterCard', 'dep': '4.5% + 0.5 EUR', 'wd': '-' },
{ 'prov': 'Visa', 'dep': '2.95%', 'wd': '-' },
{ 'prov': 'Frick Internal Transfer', 'dep': '0 EUR', 'wd': '-' },
- { 'prov': 'SEPA Frick Bank', 'dep': '0 EUR', 'wd': '-' },
- { 'prov': 'WIRE Frick Bank', 'dep': '0%', 'wd': '-' },
+ { 'prov': 'SEPA Frick Bank', 'dep': '0 EUR', 'wd': '1 EUR' },
+ { 'prov': 'WIRE Frick Bank', 'dep': '0%', 'wd': '20 EUR' },
{ 'prov': 'SEPA Weg Ag', 'dep': '-', 'wd': '1 EUR' },
],
},
+ {
+ 'group': 'gbp',
+ 'title': 'GBP',
+ 'items': [
+ { 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
+ { 'prov': 'WIRE Frick Bank', 'dep': '10 GBP', 'wd': '-' },
+ ],
+ },
{
'group': 'rub',
'title': 'RUB',
'items': [
- { 'prov': 'Payeer', 'dep': '2.49%', 'wd': '3.99%' },
+ { 'prov': 'Payeer', 'dep': '2.49%', 'wd': '3.49%' },
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Qiwi', 'dep': '1.49%', 'wd': '2.49%' },
- { 'prov': 'Yandex Money', 'dep': '1.49%', 'wd': '-' },
- { 'prov': 'AdvCash', 'dep': '0%', 'wd': '3.49%' },
+ { 'prov': 'Yandex Money', 'dep': '1.49%', 'wd': '1.95 %' },
+ { 'prov': 'AdvCash', 'dep': '0.99%', 'wd': '0.99%' },
{ 'prov': 'Visa/MasterCard', 'dep': '2.99%', 'wd': '3.99% + 60 RUB' },
],
},
@@ -433,17 +430,16 @@ module.exports = class exmo extends Exchange {
'items': [
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
{ 'prov': 'Terminal', 'dep': '2.6%', 'wd': '-' },
- { 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '-' },
{ 'prov': 'Visa/MasterCard EasyTransfer', 'dep': '-', 'wd': '2.99%' },
+ { 'prov': 'Visa/MasterCard', 'dep': '1% + 5 UAH', 'wd': '-' },
],
},
{
'group': 'kzt',
'title': 'KZT',
'items': [
+ { 'prov': 'Visa/MasterCard', 'dep': '3.5%', 'wd': '2.99% + 450 KZT' },
{ 'prov': 'EX-CODE', 'dep': '', 'wd': '0.2%' },
- { 'prov': 'Visa/MasterCard RoyalPay', 'dep': '-', 'wd': '2.99% + 450 KZT' },
- { 'prov': 'Visa/MasterCard', 'dep': '3.5%', 'wd': '-' },
{ 'prov': 'AdvCash', 'dep': '0%', 'wd': '-' },
],
},
@@ -464,6 +460,7 @@ module.exports = class exmo extends Exchange {
'50054': InsufficientFunds,
'50304': OrderNotFound, // "Order was not found '123456789'" (fetching order trades for an order that does not have trades yet)
'50173': OrderNotFound, // "Order with id X was not found." (cancelling non-existent, closed and cancelled order)
+ '50277': InvalidOrder,
'50319': InvalidOrder, // Price by order is less than permissible minimum for this pair
'50321': InvalidOrder, // Price by order is more than permissible maximum for this pair
},
@@ -473,6 +470,7 @@ module.exports = class exmo extends Exchange {
'API rate limit exceeded': RateLimitExceeded, // {"result":false,"error":"API rate limit exceeded for 99.33.55.224. Retry after 60 sec.","history":[],"begin":1579392000,"end":1579478400}
},
},
+ 'orders': {}, // orders cache / emulation
});
}
@@ -510,6 +508,9 @@ module.exports = class exmo extends Exchange {
if ((input === undefined) || (input === '-')) {
return undefined;
}
+ if (input === '') {
+ return 0;
+ }
const isPercentage = (input.indexOf ('%') >= 0);
const parts = input.split (' ');
const value = parts[0].replace ('%', '');
@@ -539,14 +540,10 @@ module.exports = class exmo extends Exchange {
const withdrawalFee = this.safeString (item, 'wd');
const depositFee = this.safeString (item, 'dep');
if (withdrawalFee !== undefined) {
- if (withdrawalFee.length > 0) {
- withdraw[code] = this.parseFixedFloatValue (withdrawalFee);
- }
+ withdraw[code] = this.parseFixedFloatValue (withdrawalFee);
}
if (depositFee !== undefined) {
- if (depositFee.length > 0) {
- deposit[code] = this.parseFixedFloatValue (depositFee);
- }
+ deposit[code] = this.parseFixedFloatValue (depositFee);
}
}
// sets fiat fees to undefined
@@ -634,15 +631,16 @@ module.exports = class exmo extends Exchange {
const response = await this.publicGetPairSettings (params);
//
// {
- // "EXM_ETH": {
- // "min_quantity": "1",
- // "max_quantity": "1000",
- // "min_price": "1",
- // "max_price": "1000",
- // "max_amount": "1000",
- // "min_amount": "1",
- // "commission_taker_percent": "0.2",
- // "commission_maker_percent": "0.2"
+ // "BTC_USD":{
+ // "min_quantity":"0.0001",
+ // "max_quantity":"1000",
+ // "min_price":"1",
+ // "max_price":"30000",
+ // "max_amount":"500000",
+ // "min_amount":"1",
+ // "price_precision":8,
+ // "commission_taker_percent":"0.4",
+ // "commission_maker_percent":"0.4"
// },
// }
//
@@ -683,7 +681,7 @@ module.exports = class exmo extends Exchange {
},
'precision': {
'amount': 8,
- 'price': 8,
+ 'price': this.safeInteger (market, 'price_precision'),
},
'info': market,
});
@@ -738,7 +736,7 @@ module.exports = class exmo extends Exchange {
return this.parseOHLCVs (candles, market, timeframe, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '5m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// "t":1584057600000,
@@ -763,16 +761,18 @@ module.exports = class exmo extends Exchange {
await this.loadMarkets ();
const response = await this.privatePostUserInfo (params);
const result = { 'info': response };
- const codes = Object.keys (this.currencies);
+ const free = this.safeValue (response, 'balances', {});
+ const used = this.safeValue (response, 'reserved', {});
+ const codes = Object.keys (free);
for (let i = 0; i < codes.length; i++) {
const code = codes[i];
const currencyId = this.currencyId (code);
const account = this.account ();
- if (currencyId in response['balances']) {
- account['free'] = this.safeFloat (response['balances'], currencyId);
+ if (currencyId in free) {
+ account['free'] = this.safeFloat (free, currencyId);
}
- if (currencyId in response['reserved']) {
- account['used'] = this.safeFloat (response['reserved'], currencyId);
+ if (currencyId in used) {
+ account['used'] = this.safeFloat (used, currencyId);
}
result[code] = account;
}
@@ -871,7 +871,7 @@ module.exports = class exmo extends Exchange {
const ticker = response[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -1068,7 +1068,7 @@ module.exports = class exmo extends Exchange {
amount = parseFloat (amount);
price = parseFloat (price);
const status = 'open';
- const order = {
+ return {
'id': id,
'info': response,
'timestamp': timestamp,
@@ -1088,60 +1088,45 @@ module.exports = class exmo extends Exchange {
'clientOrderId': undefined,
'average': undefined,
};
- this.orders[id] = order;
- return order;
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const request = { 'order_id': id };
- const response = await this.privatePostOrderCancel (this.extend (request, params));
- if (id in this.orders) {
- this.orders[id]['status'] = 'canceled';
- }
- return response;
+ return await this.privatePostOrderCancel (this.extend (request, params));
}
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- try {
- const request = {
- 'order_id': id.toString (),
- };
- const response = await this.privatePostOrderTrades (this.extend (request, params));
- //
- // {
- // "type": "buy",
- // "in_currency": "BTC",
- // "in_amount": "1",
- // "out_currency": "USD",
- // "out_amount": "100",
- // "trades": [
- // {
- // "trade_id": 3,
- // "date": 1435488248,
- // "type": "buy",
- // "pair": "BTC_USD",
- // "order_id": 12345,
- // "quantity": 1,
- // "price": 100,
- // "amount": 100
- // }
- // ]
- // }
- //
- const order = this.parseOrder (response);
- return this.extend (order, {
- 'id': id.toString (),
- });
- } catch (e) {
- if (e instanceof OrderNotFound) {
- if (id in this.orders) {
- return this.orders[id];
- }
- }
- }
- throw new OrderNotFound (this.id + ' fetchOrder order id ' + id.toString () + ' not found in cache.');
+ const request = {
+ 'order_id': id.toString (),
+ };
+ const response = await this.privatePostOrderTrades (this.extend (request, params));
+ //
+ // {
+ // "type": "buy",
+ // "in_currency": "BTC",
+ // "in_amount": "1",
+ // "out_currency": "USD",
+ // "out_amount": "100",
+ // "trades": [
+ // {
+ // "trade_id": 3,
+ // "date": 1435488248,
+ // "type": "buy",
+ // "pair": "BTC_USD",
+ // "order_id": 12345,
+ // "quantity": 1,
+ // "price": 100,
+ // "amount": 100
+ // }
+ // ]
+ // }
+ //
+ const order = this.parseOrder (response);
+ return this.extend (order, {
+ 'id': id.toString (),
+ });
}
async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -1182,48 +1167,7 @@ module.exports = class exmo extends Exchange {
return this.parseTrades (trades, market, since, limit);
}
- updateCachedOrders (openOrders, symbol) {
- // update local cache with open orders
- for (let j = 0; j < openOrders.length; j++) {
- const id = openOrders[j]['id'];
- this.orders[id] = openOrders[j];
- }
- const openOrdersIndexedById = this.indexBy (openOrders, 'id');
- const cachedOrderIds = Object.keys (this.orders);
- for (let k = 0; k < cachedOrderIds.length; k++) {
- // match each cached order to an order in the open orders array
- // possible reasons why a cached order may be missing in the open orders array:
- // - order was closed or canceled -> update cache
- // - symbol mismatch (e.g. cached BTC/USDT, fetched ETH/USDT) -> skip
- const id = cachedOrderIds[k];
- let order = this.orders[id];
- if (!(id in openOrdersIndexedById)) {
- // cached order is not in open orders array
- // if we fetched orders by symbol and it doesn't match the cached order -> won't update the cached order
- if (symbol !== undefined && symbol !== order['symbol']) {
- continue;
- }
- // order is cached but not present in the list of open orders -> mark the cached order as closed
- if (order['status'] === 'open') {
- order = this.extend (order, {
- 'status': 'closed', // likewise it might have been canceled externally (unnoticed by "us")
- 'cost': undefined,
- 'filled': order['amount'],
- 'remaining': 0.0,
- });
- if (order['cost'] === undefined) {
- if (order['filled'] !== undefined) {
- order['cost'] = order['filled'] * order['price'];
- }
- }
- this.orders[id] = order;
- }
- }
- }
- return this.toArray (this.orders);
- }
-
- async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privatePostUserOpenOrders (params);
const marketIds = Object.keys (response);
@@ -1237,19 +1181,6 @@ module.exports = class exmo extends Exchange {
const parsedOrders = this.parseOrders (response[marketId], market);
orders = this.arrayConcat (orders, parsedOrders);
}
- this.updateCachedOrders (orders, symbol);
- return this.filterBySymbolSinceLimit (this.toArray (this.orders), symbol, since, limit);
- }
-
- async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.fetchOrders (symbol, since, limit, params);
- const orders = this.filterBy (this.orders, 'status', 'open');
- return this.filterBySymbolSinceLimit (orders, symbol, since, limit);
- }
-
- async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.fetchOrders (symbol, since, limit, params);
- const orders = this.filterBy (this.orders, 'status', 'closed');
return this.filterBySymbolSinceLimit (orders, symbol, since, limit);
}
@@ -1341,15 +1272,15 @@ module.exports = class exmo extends Exchange {
}
lastTradeTimestamp = trades[numTransactions - 1]['timestamp'];
}
+ let status = this.safeString (order, 'status'); // in case we need to redefine it for canceled orders
let remaining = undefined;
if (amount !== undefined) {
remaining = amount - filled;
- }
- let status = this.safeString (order, 'status'); // in case we need to redefine it for canceled orders
- if (filled >= amount) {
- status = 'closed';
- } else {
- status = 'open';
+ if (filled >= amount) {
+ status = 'closed';
+ } else {
+ status = 'open';
+ }
}
if (market === undefined) {
market = this.getMarketFromTrades (trades);
@@ -1386,8 +1317,10 @@ module.exports = class exmo extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
diff --git a/TaskServer/node_modules/ccxt/js/exx.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/exx.js
similarity index 96%
rename from TaskServer/node_modules/ccxt/js/exx.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/exx.js
index 545adaabb..925d4a2f2 100644
--- a/TaskServer/node_modules/ccxt/js/exx.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/exx.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, AuthenticationError, ExchangeNotAvailable } = require ('./base/errors');
+const { ExchangeError, AuthenticationError, ExchangeNotAvailable, ArgumentsRequired } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -16,9 +16,16 @@ module.exports = class exx extends Exchange {
'rateLimit': 1000 / 10,
'userAgent': this.userAgents['chrome'],
'has': {
- 'fetchOrder': true,
- 'fetchTickers': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/37770292-fbf613d0-2de4-11e8-9f79-f2dc451b8ccb.jpg',
@@ -83,6 +90,7 @@ module.exports = class exx extends Exchange {
},
},
'commonCurrencies': {
+ 'DOS': 'DEMOS',
'TV': 'TIV', // Ti-Value
},
'exceptions': {
@@ -194,7 +202,7 @@ module.exports = class exx extends Exchange {
};
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -317,8 +325,10 @@ module.exports = class exx extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': order['type'],
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -349,7 +359,6 @@ module.exports = class exx extends Exchange {
'type': side,
'info': response,
}, market);
- this.orders[id] = order;
return order;
}
@@ -377,6 +386,9 @@ module.exports = class exx extends Exchange {
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
+ if (symbol === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchOpenOrders requires a symbol argument');
+ }
const market = this.market (symbol);
const request = {
'currency': market['id'],
diff --git a/TaskServer/node_modules/ccxt/js/fcoin.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/fcoin.js
similarity index 96%
rename from TaskServer/node_modules/ccxt/js/fcoin.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/fcoin.js
index 871186527..1bdb5920d 100644
--- a/TaskServer/node_modules/ccxt/js/fcoin.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/fcoin.js
@@ -20,18 +20,25 @@ module.exports = class fcoin extends Exchange {
'accountsById': undefined,
'hostname': 'fcoin.com',
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': false,
'fetchDepositAddress': false,
+ 'fetchMarkets': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
'fetchOrder': true,
- 'fetchOrders': true,
'fetchOrderBook': true,
'fetchOrderBooks': false,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTradingLimits': false,
'withdraw': false,
- 'fetchCurrencies': false,
},
'timeframes': {
'1m': 'M1',
@@ -375,16 +382,11 @@ module.exports = class fcoin extends Exchange {
if (tickerType !== undefined) {
const parts = tickerType.split ('.');
const id = parts[1];
- if (id in this.markets_by_id) {
- market = this.markets_by_id[id];
- }
+ symbol = this.safeSymbol (id, market);
}
}
const values = ticker['ticker'];
const last = this.safeFloat (values, 0);
- if (market !== undefined) {
- symbol = market['symbol'];
- }
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -443,6 +445,17 @@ module.exports = class fcoin extends Exchange {
};
}
+ async fetchTime (params = {}) {
+ const response = await this.publicGetServerTime (params);
+ //
+ // {
+ // "status": 0,
+ // "data": 1523430502977
+ // }
+ //
+ return this.safeInteger (response, 'data');
+ }
+
async fetchTrades (symbol, since = undefined, limit = 50, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
@@ -533,13 +546,9 @@ module.exports = class fcoin extends Exchange {
const id = this.safeString (order, 'id');
const side = this.safeString (order, 'side');
const status = this.parseOrderStatus (this.safeString (order, 'state'));
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
+ const marketId = this.safeString (order, 'symbol');
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
const orderType = this.safeString (order, 'type');
const timestamp = this.safeInteger (order, 'created_at');
const amount = this.safeFloat (order, 'amount');
@@ -564,14 +573,12 @@ module.exports = class fcoin extends Exchange {
const feeRebate = this.safeFloat (order, 'fees_income');
if ((feeRebate !== undefined) && (feeRebate > 0)) {
if (market !== undefined) {
- symbol = market['symbol'];
feeCurrency = (side === 'buy') ? market['quote'] : market['base'];
}
feeCost = -feeRebate;
} else {
feeCost = this.safeFloat (order, 'fill_fees');
if (market !== undefined) {
- symbol = market['symbol'];
feeCurrency = (side === 'buy') ? market['base'] : market['quote'];
}
}
@@ -584,8 +591,10 @@ module.exports = class fcoin extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': orderType,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'remaining': remaining,
@@ -636,7 +645,7 @@ module.exports = class fcoin extends Exchange {
return this.parseOrders (response['data'], market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
return [
this.safeTimestamp (ohlcv, 'id'),
this.safeFloat (ohlcv, 'open'),
@@ -664,7 +673,8 @@ module.exports = class fcoin extends Exchange {
request['before'] = this.sum (sinceInSeconds, timerange) - 1;
}
const response = await this.marketGetCandlesTimeframeSymbol (this.extend (request, params));
- return this.parseOHLCVs (response['data'], market, timeframe, since, limit);
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
nonce () {
@@ -701,7 +711,7 @@ module.exports = class fcoin extends Exchange {
auth += this.urlencode (query);
}
}
- const payload = this.stringToBase64 (this.encode (auth));
+ const payload = this.stringToBase64 (auth);
let signature = this.hmac (payload, this.encode (this.secret), 'sha1', 'binary');
signature = this.decode (this.stringToBase64 (signature));
headers = {
diff --git a/TaskServer/node_modules/ccxt/js/fcoinjp.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/fcoinjp.js
similarity index 100%
rename from TaskServer/node_modules/ccxt/js/fcoinjp.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/fcoinjp.js
diff --git a/TaskServer/node_modules/ccxt/js/flowbtc.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/flowbtc.js
similarity index 96%
rename from TaskServer/node_modules/ccxt/js/flowbtc.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/flowbtc.js
index d4ca90c05..d38ebfea9 100644
--- a/TaskServer/node_modules/ccxt/js/flowbtc.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/flowbtc.js
@@ -16,10 +16,17 @@ module.exports = class flowbtc extends Exchange {
'version': 'v1',
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/28162465-cd815d4c-67cf-11e7-8e57-438bea0523a2.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87443317-01c0d080-c5fe-11ea-95c2-9ebe1a8fafd9.jpg',
'api': 'https://publicapi.flowbtc.com.br',
'www': 'https://www.flowbtc.com.br',
'doc': 'https://www.flowbtc.com.br/api.html',
diff --git a/TaskServer/node_modules/ccxt/js/foxbit.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/foxbit.js
similarity index 97%
rename from TaskServer/node_modules/ccxt/js/foxbit.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/foxbit.js
index 452fd9cdd..5830969a3 100644
--- a/TaskServer/node_modules/ccxt/js/foxbit.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/foxbit.js
@@ -14,13 +14,19 @@ module.exports = class foxbit extends Exchange {
'name': 'FoxBit',
'countries': [ 'BR' ],
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'rateLimit': 1000,
'version': 'v1',
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27991413-11b40d42-647f-11e7-91ee-78ced874dd09.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87443320-01c0d080-c5fe-11ea-92e2-4ef56d32b026.jpg',
'api': {
'public': 'https://api.blinktrade.com/api',
'private': 'https://api.blinktrade.com/tapi',
diff --git a/TaskServer/node_modules/ccxt/js/ftx.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/ftx.js
similarity index 76%
rename from TaskServer/node_modules/ccxt/js/ftx.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/ftx.js
index bdfa52251..8e3992ac5 100644
--- a/TaskServer/node_modules/ccxt/js/ftx.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/ftx.js
@@ -4,7 +4,7 @@
const Exchange = require ('./base/Exchange');
const { TICK_SIZE } = require ('./base/functions/number');
-const { ExchangeError, InvalidOrder, BadRequest, InsufficientFunds, OrderNotFound } = require ('./base/errors');
+const { ExchangeError, InvalidOrder, BadRequest, InsufficientFunds, OrderNotFound, AuthenticationError } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -17,12 +17,13 @@ module.exports = class ftx extends Exchange {
'rateLimit': 100,
'certified': true,
'pro': true,
+ 'hostname': 'ftx.com', // or ftx.us
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/67149189-df896480-f2b0-11e9-8816-41593e17f9ec.jpg',
'www': 'https://ftx.com',
'api': {
- 'public': 'https://ftx.com',
- 'private': 'https://ftx.com',
+ 'public': 'https://{hostname}',
+ 'private': 'https://{hostname}',
},
'doc': 'https://github.com/ftexchange/ftx',
'fees': 'https://ftexchange.zendesk.com/hc/en-us/articles/360024479432-Fees',
@@ -30,11 +31,16 @@ module.exports = class ftx extends Exchange {
},
'has': {
'cancelAllOrders': true,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': false,
'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
'fetchFundingFees': false,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
@@ -66,12 +72,24 @@ module.exports = class ftx extends Exchange {
'markets/{market_name}/orderbook', // ?depth={depth}
'markets/{market_name}/trades', // ?limit={limit}&start_time={start_time}&end_time={end_time}
'markets/{market_name}/candles', // ?resolution={resolution}&limit={limit}&start_time={start_time}&end_time={end_time}
+ // futures
'futures',
'futures/{future_name}',
'futures/{future_name}/stats',
'funding_rates',
+ 'indexes/{index_name}/weights',
+ 'expired_futures',
+ 'indexes/{market_name}/candles', // ?resolution={resolution}&limit={limit}&start_time={start_time}&end_time={end_time}
+ // leverage tokens
'lt/tokens',
'lt/{token_name}',
+ // options
+ 'options/requests',
+ 'options/trades',
+ 'stats/24h_options_volume',
+ 'options/historical_volumes/BTC',
+ 'options/open_interest/BTC',
+ 'options/historical_open_interest/BTC',
],
},
'private': {
@@ -80,6 +98,7 @@ module.exports = class ftx extends Exchange {
'positions',
'wallet/coins',
'wallet/balances',
+ 'wallet/all_balances',
'wallet/deposit_address/{coin}',
'wallet/deposits',
'wallet/withdrawals',
@@ -88,32 +107,60 @@ module.exports = class ftx extends Exchange {
'orders/{order_id}',
'orders/by_client_id/{client_order_id}',
'conditional_orders', // ?market={market}
+ 'conditional_orders/{conditional_order_id}/triggers',
'conditional_orders/history', // ?market={market}
'fills', // ?market={market}
'funding_payments',
+ // leverage tokens
'lt/balances',
'lt/creations',
'lt/redemptions',
+ // subaccounts
'subaccounts',
'subaccounts/{nickname}/balances',
+ // otc
+ 'otc/quotes/{quoteId}',
+ // options
+ 'options/my_requests',
+ 'options/requests/{request_id}/quotes',
+ 'options/my_quotes',
+ 'options/account_info',
+ 'options/positions',
+ 'options/fills',
],
'post': [
'account/leverage',
'wallet/withdrawals',
'orders',
'conditional_orders',
+ 'orders/{order_id}/modify',
+ 'orders/by_client_id/{client_order_id}/modify',
+ 'conditional_orders/{order_id}/modify',
+ // leverage tokens
'lt/{token_name}/create',
'lt/{token_name}/redeem',
+ // subaccounts
'subaccounts',
'subaccounts/update_name',
'subaccounts/transfer',
+ // otc
+ 'otc/quotes/{quote_id}/accept',
+ 'otc/quotes',
+ // options
+ 'options/requests',
+ 'options/requests/{request_id}/quotes',
+ 'options/quotes/{quote_id}/accept',
],
'delete': [
'orders/{order_id}',
'orders/by_client_id/{client_order_id}',
'orders',
'conditional_orders/{order_id}',
+ // subaccounts
'subaccounts',
+ // options
+ 'options/requests/{request_id}',
+ 'options/quotes/{quote_id}',
],
},
},
@@ -148,11 +195,13 @@ module.exports = class ftx extends Exchange {
},
'exceptions': {
'exact': {
+ 'Not logged in': AuthenticationError, // {"error":"Not logged in","success":false}
'Not enough balances': InsufficientFunds, // {"error":"Not enough balances","success":false}
'InvalidPrice': InvalidOrder, // {"error":"Invalid price","success":false}
'Size too small': InvalidOrder, // {"error":"Size too small","success":false}
'Missing parameter price': InvalidOrder, // {"error":"Missing parameter price","success":false}
'Order not found': OrderNotFound, // {"error":"Order not found","success":false}
+ 'Order already closed': InvalidOrder, // {"error":"Order already closed","success":false}
},
'broad': {
'Invalid parameter': BadRequest, // {"error":"Invalid parameter start_time","success":false}
@@ -175,6 +224,10 @@ module.exports = class ftx extends Exchange {
'fetchOrders': {
'method': 'privateGetOrdersHistory', // privateGetConditionalOrdersHistory
},
+ 'sign': {
+ 'ftx.com': 'FTX',
+ 'ftx.us': 'FTXUS',
+ },
},
});
}
@@ -492,7 +545,7 @@ module.exports = class ftx extends Exchange {
return this.parseOrderBook (result);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// {
// "close":177.23,
@@ -514,12 +567,29 @@ module.exports = class ftx extends Exchange {
];
}
+ getMarketId (symbol, key, params = {}) {
+ const parts = this.getMarketParams (symbol, key, params);
+ return this.safeString (parts, 1, symbol);
+ }
+
+ getMarketParams (symbol, key, params = {}) {
+ let market = undefined;
+ let marketId = undefined;
+ if (symbol in this.markets) {
+ market = this.market (symbol);
+ marketId = market['id'];
+ } else {
+ marketId = this.safeString (params, key, symbol);
+ }
+ return [ market, marketId ];
+ }
+
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
- const market = this.market (symbol);
+ const [ market, marketId ] = this.getMarketParams (symbol, 'market_name', params);
const request = {
- 'market_name': market['id'],
'resolution': this.timeframes[timeframe],
+ 'market_name': marketId,
};
// max 1501 candles, including the current candle when since is not specified
limit = (limit === undefined) ? 1501 : limit;
@@ -655,9 +725,9 @@ module.exports = class ftx extends Exchange {
async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
- const market = this.market (symbol);
+ const [ market, marketId ] = this.getMarketParams (symbol, 'market_name', params);
const request = {
- 'market_name': market['id'],
+ 'market_name': marketId,
};
if (since !== undefined) {
request['start_time'] = parseInt (since / 1000);
@@ -778,13 +848,14 @@ module.exports = class ftx extends Exchange {
'new': 'open',
'open': 'open',
'closed': 'closed', // filled or canceled
+ 'triggered': 'closed',
};
return this.safeString (statuses, status, status);
}
parseOrder (order, market = undefined) {
//
- // limit orders - fetchOrder, fetchOrders, fetchOpenOrders, createOrder
+ // limit orders - fetchOrder, fetchOrders, fetchOpenOrders, createOrder, editOrder
//
// {
// "createdAt": "2019-03-05T09:56:55.728933+00:00",
@@ -844,23 +915,80 @@ module.exports = class ftx extends Exchange {
// "reduceOnly": false
// }
//
+ // editOrder (conditional, stop, trailing stop, take profit)
+ //
+ // {
+ // "createdAt": "2019-03-05T09:56:55.728933+00:00",
+ // "future": "XRP-PERP",
+ // "id": 9596912,
+ // "market": "XRP-PERP",
+ // "triggerPrice": 0.306225,
+ // "orderId": null,
+ // "side": "sell",
+ // "size": 31431,
+ // "status": "open",
+ // "type": "stop",
+ // "orderPrice": null,
+ // "error": null,
+ // "triggeredAt": null,
+ // "reduceOnly": false,
+ // "orderType": "market",
+ // "filledSize": 0,
+ // "avgFillPrice": null,
+ // "retryUntilFilled": false
+ // }
+ //
+ // canceled order with a closed status
+ //
+ // {
+ // "avgFillPrice":null,
+ // "clientId":null,
+ // "createdAt":"2020-09-01T13:45:57.119695+00:00",
+ // "filledSize":0.0,
+ // "future":null,
+ // "id":8553541288,
+ // "ioc":false,
+ // "liquidation":false,
+ // "market":"XRP/USDT",
+ // "postOnly":false,
+ // "price":0.5,
+ // "reduceOnly":false,
+ // "remainingSize":0.0,
+ // "side":"sell",
+ // "size":46.0,
+ // "status":"closed",
+ // "type":"limit"
+ // }
+ //
const id = this.safeString (order, 'id');
const timestamp = this.parse8601 (this.safeString (order, 'createdAt'));
+ let status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const amount = this.safeFloat (order, 'size');
const filled = this.safeFloat (order, 'filledSize');
- const remaining = this.safeFloat (order, 'remainingSize');
+ let remaining = this.safeFloat (order, 'remainingSize');
+ if ((remaining === 0.0) && (amount !== undefined) && (filled !== undefined)) {
+ remaining = Math.max (amount - filled, 0);
+ if (remaining > 0) {
+ status = 'canceled';
+ }
+ }
let symbol = undefined;
const marketId = this.safeString (order, 'market');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ symbol = market['symbol'];
+ } else {
+ // support for delisted market ids
+ // https://github.com/ccxt/ccxt/issues/7113
+ symbol = marketId;
+ }
}
if ((symbol === undefined) && (market !== undefined)) {
symbol = market['symbol'];
}
- const status = this.parseOrderStatus (this.safeString (order, 'status'));
const side = this.safeString (order, 'side');
const type = this.safeString (order, 'type');
- const amount = this.safeFloat (order, 'size');
const average = this.safeFloat (order, 'avgFillPrice');
const price = this.safeFloat2 (order, 'price', 'triggerPrice', average);
let cost = undefined;
@@ -869,6 +997,7 @@ module.exports = class ftx extends Exchange {
}
const lastTradeTimestamp = this.parse8601 (this.safeString (order, 'triggeredAt'));
const clientOrderId = this.safeString (order, 'clientId');
+ const stopPrice = this.safeFloat (order, 'triggerPrice');
return {
'info': order,
'id': id,
@@ -878,8 +1007,10 @@ module.exports = class ftx extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'amount': amount,
'cost': cost,
'average': average,
@@ -905,6 +1036,11 @@ module.exports = class ftx extends Exchange {
// 'postOnly': false, // optional, default is false, limit or market orders only
// 'clientId': 'abcdef0123456789', // string, optional, client order id, limit or market orders only
};
+ const clientOrderId = this.safeString2 (params, 'clientId', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['clientId'] = clientOrderId;
+ params = this.omit (params, [ 'clientId', 'clientOrderId' ]);
+ }
let priceToPrecision = undefined;
if (price !== undefined) {
priceToPrecision = parseFloat (this.priceToPrecision (symbol, price));
@@ -980,6 +1116,104 @@ module.exports = class ftx extends Exchange {
return this.parseOrder (result, market);
}
+ async editOrder (id, symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {};
+ let method = undefined;
+ const clientOrderId = this.safeString2 (params, 'client_order_id', 'clientOrderId');
+ const triggerPrice = this.safeFloat (params, 'triggerPrice');
+ const orderPrice = this.safeFloat (params, 'orderPrice');
+ const trailValue = this.safeFloat (params, 'trailValue');
+ params = this.omit (params, [ 'client_order_id', 'clientOrderId', 'triggerPrice', 'orderPrice', 'trailValue' ]);
+ const triggerPriceIsDefined = (triggerPrice !== undefined);
+ const orderPriceIsDefined = (orderPrice !== undefined);
+ const trailValueIsDefined = (trailValue !== undefined);
+ if (triggerPriceIsDefined || orderPriceIsDefined || trailValueIsDefined) {
+ method = 'privatePostConditionalOrdersOrderIdModify';
+ request['order_id'] = id;
+ if (triggerPriceIsDefined) {
+ request['triggerPrice'] = parseFloat (this.priceToPrecision (symbol, triggerPrice));
+ }
+ if (orderPriceIsDefined) {
+ // only for stop limit or take profit limit orders
+ request['orderPrice'] = parseFloat (this.priceToPrecision (symbol, orderPrice));
+ }
+ if (trailValueIsDefined) {
+ // negative for sell orders, positive for buy orders
+ request['trailValue'] = parseFloat (this.priceToPrecision (symbol, trailValue));
+ }
+ } else {
+ if (clientOrderId === undefined) {
+ method = 'privatePostOrdersByClientIdClientOrderIdModify';
+ request['client_order_id'] = clientOrderId;
+ // request['clientId'] = clientOrderId;
+ } else {
+ method = 'privatePostOrdersOrderIdModify';
+ request['order_id'] = id;
+ }
+ if (price !== undefined) {
+ request['price'] = parseFloat (this.priceToPrecision (symbol, price));
+ }
+ }
+ if (amount !== undefined) {
+ request['size'] = parseFloat (this.amountToPrecision (symbol, amount));
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // regular order
+ //
+ // {
+ // "success": true,
+ // "result": {
+ // "createdAt": "2019-03-05T11:56:55.728933+00:00",
+ // "filledSize": 0,
+ // "future": "XRP-PERP",
+ // "id": 9596932,
+ // "market": "XRP-PERP",
+ // "price": 0.326525,
+ // "remainingSize": 31431,
+ // "side": "sell",
+ // "size": 31431,
+ // "status": "open",
+ // "type": "limit",
+ // "reduceOnly": false,
+ // "ioc": false,
+ // "postOnly": false,
+ // "clientId": null,
+ // }
+ // }
+ //
+ // conditional trigger order
+ //
+ // {
+ // "success": true,
+ // "result": {
+ // "createdAt": "2019-03-05T09:56:55.728933+00:00",
+ // "future": "XRP-PERP",
+ // "id": 9596912,
+ // "market": "XRP-PERP",
+ // "triggerPrice": 0.306225,
+ // "orderId": null,
+ // "side": "sell",
+ // "size": 31431,
+ // "status": "open",
+ // "type": "stop",
+ // "orderPrice": null,
+ // "error": null,
+ // "triggeredAt": null,
+ // "reduceOnly": false,
+ // "orderType": "market",
+ // "filledSize": 0,
+ // "avgFillPrice": null,
+ // "retryUntilFilled": false
+ // }
+ // }
+ //
+ const result = this.safeValue (response, 'result', {});
+ return this.parseOrder (result, market);
+ }
+
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const request = {
@@ -991,10 +1225,17 @@ module.exports = class ftx extends Exchange {
const defaultMethod = this.safeString (options, 'method', 'privateDeleteOrdersOrderId');
let method = this.safeString (params, 'method', defaultMethod);
const type = this.safeValue (params, 'type');
- if ((type === 'stop') || (type === 'trailingStop') || (type === 'takeProfit')) {
- method = 'privateDeleteConditionalOrdersOrderId';
+ const clientOrderId = this.safeValue2 (params, 'client_order_id', 'clientOrderId');
+ if (clientOrderId === undefined) {
+ request['order_id'] = parseInt (id);
+ if ((type === 'stop') || (type === 'trailingStop') || (type === 'takeProfit')) {
+ method = 'privateDeleteConditionalOrdersOrderId';
+ }
+ } else {
+ request['client_order_id'] = clientOrderId;
+ method = 'privateDeleteOrdersByClientIdClientOrderId';
}
- const query = this.omit (params, [ 'method', 'type' ]);
+ const query = this.omit (params, [ 'method', 'type', 'client_order_id', 'clientOrderId' ]);
const response = await this[method] (this.extend (request, query));
//
// {
@@ -1013,10 +1254,9 @@ module.exports = class ftx extends Exchange {
'conditionalOrdersOnly': false, // cancel conditional orders only
'limitOrdersOnly': false, // cancel existing limit orders (non-conditional orders) only
};
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['market'] = market['id'];
+ const marketId = this.getMarketId (symbol, 'market', params);
+ if (marketId !== undefined) {
+ request['market'] = marketId;
}
const response = await this.privateDeleteOrders (this.extend (request, params));
const result = this.safeValue (response, 'result', {});
@@ -1031,10 +1271,17 @@ module.exports = class ftx extends Exchange {
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- const request = {
- 'order_id': id,
- };
- const response = await this.privateGetOrdersOrderId (this.extend (request, params));
+ const request = {};
+ const clientOrderId = this.safeValue2 (params, 'client_order_id', 'clientOrderId');
+ let method = 'privateGetOrdersOrderId';
+ if (clientOrderId === undefined) {
+ request['order_id'] = id;
+ } else {
+ request['client_order_id'] = clientOrderId;
+ params = this.omit (params, [ 'client_order_id', 'clientOrderId']);
+ method = 'privateGetOrdersByClientIdClientOrderId';
+ }
+ const response = await this[method] (this.extend (request, params));
//
// {
// "success": true,
@@ -1065,10 +1312,9 @@ module.exports = class ftx extends Exchange {
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['market'] = market['id'];
+ const [ market, marketId ] = this.getMarketParams (symbol, 'market', params);
+ if (marketId !== undefined) {
+ request['market'] = marketId;
}
// support for canceling conditional orders
// https://github.com/ccxt/ccxt/issues/6669
@@ -1113,10 +1359,9 @@ module.exports = class ftx extends Exchange {
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
- let market = undefined;
- if (symbol !== undefined) {
- market = this.market (symbol);
- request['market'] = market['id'];
+ const [ market, marketId ] = this.getMarketParams (symbol, 'market', params);
+ if (marketId !== undefined) {
+ request['market'] = marketId;
}
if (limit !== undefined) {
request['limit'] = limit; // default 100, max 100
@@ -1166,10 +1411,11 @@ module.exports = class ftx extends Exchange {
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
- const market = this.market (symbol);
- const request = {
- 'market': market['id'],
- };
+ const [ market, marketId ] = this.getMarketParams (symbol, 'market', params);
+ const request = {};
+ if (marketId !== undefined) {
+ request['market'] = marketId;
+ }
if (limit !== undefined) {
request['limit'] = limit;
}
@@ -1215,6 +1461,9 @@ module.exports = class ftx extends Exchange {
// 'password': 'string', // optional withdrawal password if it is required for your account
// 'code': '192837', // optional 2fa code if it is required for your account
};
+ if (this.password !== undefined) {
+ request['password'] = this.password;
+ }
if (tag !== undefined) {
request['tag'] = tag;
}
@@ -1239,6 +1488,60 @@ module.exports = class ftx extends Exchange {
return this.parseTransaction (result, currency);
}
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccount (params);
+ //
+ // {
+ // "result":{
+ // "backstopProvider":false,
+ // "chargeInterestOnNegativeUsd":false,
+ // "collateral":2830.2567913677476,
+ // "freeCollateral":2829.670741867416,
+ // "initialMarginRequirement":0.05,
+ // "leverage":20.0,
+ // "liquidating":false,
+ // "maintenanceMarginRequirement":0.03,
+ // "makerFee":0.0,
+ // "marginFraction":null,
+ // "openMarginFraction":null,
+ // "positionLimit":null,
+ // "positionLimitUsed":null,
+ // "positions":[
+ // {
+ // "collateralUsed":0.0,
+ // "cost":0.0,
+ // "entryPrice":null,
+ // "estimatedLiquidationPrice":null,
+ // "future":"XRP-PERP",
+ // "initialMarginRequirement":0.05,
+ // "longOrderSize":0.0,
+ // "maintenanceMarginRequirement":0.03,
+ // "netSize":0.0,
+ // "openSize":0.0,
+ // "realizedPnl":0.016,
+ // "shortOrderSize":0.0,
+ // "side":"buy",
+ // "size":0.0,
+ // "unrealizedPnl":0.0,
+ // }
+ // ],
+ // "spotLendingEnabled":false,
+ // "spotMarginEnabled":false,
+ // "takerFee":0.0007,
+ // "totalAccountValue":2830.2567913677476,
+ // "totalPositionSize":0.0,
+ // "useFttCollateral":true,
+ // "username":"igor.kroitor@gmail.com"
+ // },
+ // "success":true
+ // }
+ //
+ const result = this.safeValue (response, 'result', {});
+ // todo unify parsePosition/parsePositions
+ return this.safeValue (result, 'positions', []);
+ }
+
async fetchDepositAddress (code, params = {}) {
await this.loadMarkets ();
const currency = this.currency (code);
@@ -1276,7 +1579,7 @@ module.exports = class ftx extends Exchange {
return this.safeString (statuses, status, status);
}
- parseTransaction (transaction) {
+ parseTransaction (transaction, currency = undefined) {
//
// fetchDeposits
//
@@ -1308,14 +1611,19 @@ module.exports = class ftx extends Exchange {
// }
//
const code = this.safeCurrencyCode (this.safeString (transaction, 'coin'));
- const id = this.safeInteger (transaction, 'id');
+ const id = this.safeString (transaction, 'id');
const amount = this.safeFloat (transaction, 'size');
const status = this.parseTransactionStatus (this.safeString (transaction, 'status'));
const timestamp = this.parse8601 (this.safeString (transaction, 'time'));
const txid = this.safeString (transaction, 'txid');
- const address = this.safeString (transaction, 'address');
- const tag = this.safeString (transaction, 'tag');
+ let tag = undefined;
+ let address = this.safeValue (transaction, 'address');
+ if (typeof address !== 'string') {
+ tag = this.safeString (address, 'tag');
+ address = this.safeString (address, 'address');
+ }
const fee = this.safeFloat (transaction, 'fee');
+ const type = ('destinationName' in transaction) ? 'withdrawal' : 'deposit';
return {
'info': transaction,
'id': id,
@@ -1323,12 +1631,12 @@ module.exports = class ftx extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'addressFrom': undefined,
- 'address': undefined,
+ 'address': address,
'addressTo': address,
'tagFrom': undefined,
'tag': tag,
- 'tagTo': undefined,
- 'type': undefined,
+ 'tagTo': tag,
+ 'type': type,
'amount': amount,
'currency': code,
'status': status,
@@ -1362,10 +1670,14 @@ module.exports = class ftx extends Exchange {
// }
//
const result = this.safeValue (response, 'result', []);
- return this.parseTransactions (result);
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ return this.parseTransactions (result, currency, since, limit);
}
- async fetchWithdrawals (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privateGetWalletWithdrawals (params);
//
@@ -1385,13 +1697,18 @@ module.exports = class ftx extends Exchange {
// }
//
const result = this.safeValue (response, 'result', []);
- return this.parseTransactions (result);
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ }
+ return this.parseTransactions (result, currency, since, limit);
}
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
let request = '/api/' + this.implodeParams (path, params);
const query = this.omit (params, this.extractParams (path));
- let url = this.urls['api'][api] + request;
+ const baseUrl = this.implodeParams (this.urls['api'][api], { 'hostname': this.hostname });
+ let url = baseUrl + request;
if (method !== 'POST') {
if (Object.keys (query).length) {
const suffix = '?' + this.urlencode (query);
@@ -1403,17 +1720,21 @@ module.exports = class ftx extends Exchange {
this.checkRequiredCredentials ();
const timestamp = this.milliseconds ().toString ();
let auth = timestamp + method + request;
- headers = {
- 'FTX-KEY': this.apiKey,
- 'FTX-TS': timestamp,
- };
- if (method === 'POST') {
+ headers = {};
+ if ((method === 'POST') || (method === 'DELETE')) {
body = this.json (query);
auth += body;
headers['Content-Type'] = 'application/json';
}
const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256');
- headers['FTX-SIGN'] = signature;
+ const options = this.safeValue (this.options, 'sign', {});
+ const headerPrefix = this.safeString (options, this.hostname, 'FTX');
+ const keyField = headerPrefix + '-KEY';
+ const tsField = headerPrefix + '-TS';
+ const signField = headerPrefix + '-SIGN';
+ headers[keyField] = this.apiKey;
+ headers[tsField] = timestamp;
+ headers[signField] = signature;
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
diff --git a/TaskServer/node_modules/ccxt/js/gateio.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/gateio.js
similarity index 87%
rename from TaskServer/node_modules/ccxt/js/gateio.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/gateio.js
index 6a651080c..d03f929d8 100644
--- a/TaskServer/node_modules/ccxt/js/gateio.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/gateio.js
@@ -17,22 +17,30 @@ module.exports = class gateio extends Exchange {
'rateLimit': 1000,
'pro': true,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'createMarketOrder': false,
- 'fetchTickers': true,
- 'withdraw': true,
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
- 'fetchTransactions': true,
'createDepositAddress': true,
- 'fetchDepositAddress': true,
+ 'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': false,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
'fetchOHLCV': true,
'fetchOpenOrders': true,
- 'fetchOrderTrades': true,
- 'fetchOrders': true,
'fetchOrder': true,
- 'fetchMyTrades': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': 60,
@@ -67,6 +75,7 @@ module.exports = class gateio extends Exchange {
'get': [
'candlestick2/{id}',
'pairs',
+ 'coininfo',
'marketinfo',
'marketlist',
'coininfo',
@@ -144,7 +153,6 @@ module.exports = class gateio extends Exchange {
},
},
'options': {
- 'fetchTradesMethod': 'public_get_tradehistory_id', // 'public_get_tradehistory_id_tid'
'limits': {
'cost': {
'min': {
@@ -156,12 +164,94 @@ module.exports = class gateio extends Exchange {
},
},
'commonCurrencies': {
+ 'BOX': 'DefiBox',
'BTCBEAR': 'BEAR',
'BTCBULL': 'BULL',
+ 'TNC': 'Trinity Network Credit',
},
});
}
+ async fetchCurrencies (params = {}) {
+ const response = await this.publicGetCoininfo (params);
+ //
+ // {
+ // "result":"true",
+ // "coins":[
+ // {
+ // "CNYX":{
+ // "delisted":0,
+ // "withdraw_disabled":1,
+ // "withdraw_delayed":0,
+ // "deposit_disabled":0,
+ // "trade_disabled":0
+ // }
+ // },
+ // {
+ // "USDT_ETH":{
+ // "delisted":0,
+ // "withdraw_disabled":1,
+ // "withdraw_delayed":0,
+ // "deposit_disabled":0,
+ // "trade_disabled":1
+ // }
+ // }
+ // ]
+ // }
+ //
+ const coins = this.safeValue (response, 'coins');
+ if (!coins) {
+ throw new ExchangeError (this.id + ' fetchCurrencies got an unrecognized response');
+ }
+ const result = {};
+ for (let i = 0; i < coins.length; i++) {
+ const coin = coins[i];
+ const ids = Object.keys (coin);
+ for (let j = 0; j < ids.length; j++) {
+ const id = ids[j];
+ const currency = coin[id];
+ const code = this.safeCurrencyCode (id);
+ const delisted = this.safeValue (currency, 'delisted', 0);
+ const withdrawDisabled = this.safeValue (currency, 'withdraw_disabled', 0);
+ const depositDisabled = this.safeValue (currency, 'deposit_disabled', 0);
+ const tradeDisabled = this.safeValue (currency, 'trade_disabled', 0);
+ const listed = (delisted === 0);
+ const withdrawEnabled = (withdrawDisabled === 0);
+ const depositEnabled = (depositDisabled === 0);
+ const tradeEnabled = (tradeDisabled === 0);
+ const active = listed && withdrawEnabled && depositEnabled && tradeEnabled;
+ result[code] = {
+ 'id': id,
+ 'code': code,
+ 'active': active,
+ 'info': currency,
+ 'name': undefined,
+ 'fee': undefined,
+ 'precision': undefined,
+ 'limits': {
+ 'amount': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'withdraw': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ };
+ }
+ }
+ return result;
+ }
+
async fetchMarkets (params = {}) {
const response = await this.publicGetMarketinfo (params);
//
@@ -209,7 +299,7 @@ module.exports = class gateio extends Exchange {
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
const precision = {
- 'amount': 8,
+ 'amount': this.safeInteger (details, 'amount_decimal_places'),
'price': this.safeInteger (details, 'decimal_places'),
};
const amountLimits = {
@@ -284,15 +374,15 @@ module.exports = class gateio extends Exchange {
return this.parseOrderBook (response);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
// they return [ Timestamp, Volume, Close, High, Low, Open ]
return [
- parseInt (ohlcv[0]), // t
- parseFloat (ohlcv[5]), // o
- parseFloat (ohlcv[3]), // h
- parseFloat (ohlcv[4]), // l
- parseFloat (ohlcv[2]), // c
- parseFloat (ohlcv[1]), // v
+ this.safeInteger (ohlcv, 0), // t
+ this.safeFloat (ohlcv, 5), // o
+ this.safeFloat (ohlcv, 3), // h
+ this.safeFloat (ohlcv, 4), // l
+ this.safeFloat (ohlcv, 2), // c
+ this.safeFloat (ohlcv, 1), // v
];
}
@@ -376,22 +466,11 @@ module.exports = class gateio extends Exchange {
const ids = Object.keys (response);
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- const [ baseId, quoteId ] = id.split ('_');
- let base = baseId.toUpperCase ();
- let quote = quoteId.toUpperCase ();
- base = this.safeCurrencyCode (base);
- quote = this.safeCurrencyCode (quote);
- const symbol = base + '/' + quote;
- let market = undefined;
- if (symbol in this.markets) {
- market = this.markets[symbol];
- }
- if (id in this.markets_by_id) {
- market = this.markets_by_id[id];
- }
+ const market = this.safeMarket (id, undefined, '_');
+ const symbol = market['symbol'];
result[symbol] = this.parseTicker (response[id], market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -477,7 +556,12 @@ module.exports = class gateio extends Exchange {
const request = {
'id': market['id'],
};
- const method = this.safeString (this.options, 'fetchTradesMethod', 'public_get_tradehistory_id');
+ let method = undefined;
+ if ('tid' in params) {
+ method = 'publicGetTradeHistoryIdTid';
+ } else {
+ method = 'publicGetTradeHistoryId';
+ }
const response = await this[method] (this.extend (request, params));
return this.parseTrades (response['data'], market, since, limit);
}
@@ -568,14 +652,8 @@ module.exports = class gateio extends Exchange {
// }
//
const id = this.safeString2 (order, 'orderNumber', 'id');
- let symbol = undefined;
const marketId = this.safeString (order, 'currencyPair');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '_');
const timestamp = this.safeTimestamp2 (order, 'timestamp', 'ctime');
const lastTradeTimestamp = this.safeTimestamp (order, 'mtime');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
@@ -611,8 +689,10 @@ module.exports = class gateio extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': undefined,
'amount': amount,
'filled': filled,
@@ -750,29 +830,6 @@ module.exports = class gateio extends Exchange {
};
}
- sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
- const prefix = (api === 'private') ? (api + '/') : '';
- let url = this.urls['api'][api] + this.version + '/1/' + prefix + this.implodeParams (path, params);
- const query = this.omit (params, this.extractParams (path));
- if (api === 'public') {
- if (Object.keys (query).length) {
- url += '?' + this.urlencode (query);
- }
- } else {
- this.checkRequiredCredentials ();
- const nonce = this.nonce ();
- const request = { 'nonce': nonce };
- body = this.urlencode (this.extend (request, query));
- const signature = this.hmac (this.encode (body), this.encode (this.secret), 'sha512');
- headers = {
- 'Key': this.apiKey,
- 'Sign': signature,
- 'Content-Type': 'application/x-www-form-urlencoded',
- };
- }
- return { 'url': url, 'method': method, 'body': body, 'headers': headers };
- }
-
async fetchTransactionsByType (type = undefined, code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {};
@@ -897,4 +954,30 @@ module.exports = class gateio extends Exchange {
this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
}
}
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const prefix = (api === 'private') ? (api + '/') : '';
+ let url = this.urls['api'][api] + this.version + '/1/' + prefix + this.implodeParams (path, params);
+ const query = this.omit (params, this.extractParams (path));
+ if (api === 'public') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else {
+ this.checkRequiredCredentials ();
+ const nonce = this.nonce ();
+ const request = { 'nonce': nonce };
+ body = this.rawencode (this.extend (request, query));
+ // gateio does not like the plus sign in the URL query
+ // https://github.com/ccxt/ccxt/issues/4529
+ body = body.replace ('+', ' ');
+ const signature = this.hmac (this.encode (body), this.encode (this.secret), 'sha512');
+ headers = {
+ 'Key': this.apiKey,
+ 'Sign': signature,
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ };
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
};
diff --git a/TaskServer/node_modules/ccxt/js/gemini.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/gemini.js
similarity index 68%
rename from TaskServer/node_modules/ccxt/js/gemini.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/gemini.js
index 6e07ab638..a0894c364 100644
--- a/TaskServer/node_modules/ccxt/js/gemini.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/gemini.js
@@ -3,7 +3,8 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, BadRequest, OrderNotFound, InvalidOrder, InvalidNonce, InsufficientFunds, AuthenticationError, PermissionDenied, NotSupported, OnMaintenance, RateLimitExceeded } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, BadRequest, OrderNotFound, InvalidOrder, InvalidNonce, InsufficientFunds, AuthenticationError, PermissionDenied, NotSupported, OnMaintenance, RateLimitExceeded, ExchangeNotAvailable } = require ('./base/errors');
+const { TICK_SIZE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -16,22 +17,29 @@ module.exports = class gemini extends Exchange {
'rateLimit': 1500, // 200 for private API
'version': 'v1',
'has': {
- 'fetchDepositAddress': false,
- 'createDepositAddress': true,
+ 'cancelOrder': true,
'CORS': false,
- 'fetchBidsAsks': false,
- 'fetchTickers': false,
- 'fetchMyTrades': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': false,
+ 'createDepositAddress': true,
'createMarketOrder': false,
- 'withdraw': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchBidsAsks': false,
+ 'fetchClosedOrders': false,
+ 'fetchDepositAddress': false,
+ 'fetchDeposits': false,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTransactions': true,
'fetchWithdrawals': false,
- 'fetchDeposits': false,
- 'fetchOHLCV': true,
+ 'withdraw': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27816857-ce7be644-6096-11e7-82d6-3c257263229c.jpg',
@@ -48,7 +56,11 @@ module.exports = class gemini extends Exchange {
'test': {
'public': 'https://api.sandbox.gemini.com',
'private': 'https://api.sandbox.gemini.com',
- 'web': 'https://docs.sandbox.gemini.com',
+ // use the true doc instead of the sandbox doc
+ // since they differ in parsing
+ // https://github.com/ccxt/ccxt/issues/7874
+ // https://github.com/ccxt/ccxt/issues/7894
+ 'web': 'https://docs.gemini.com',
},
'fees': [
'https://gemini.com/api-fee-schedule',
@@ -65,6 +77,7 @@ module.exports = class gemini extends Exchange {
'public': {
'get': [
'v1/symbols',
+ 'v1/pricefeed',
'v1/pubticker/{symbol}',
'v1/book/{symbol}',
'v1/trades/{symbol}',
@@ -94,6 +107,7 @@ module.exports = class gemini extends Exchange {
],
},
},
+ 'precisionMode': TICK_SIZE,
'fees': {
'trading': {
'taker': 0.0035,
@@ -107,7 +121,7 @@ module.exports = class gemini extends Exchange {
'406': InsufficientFunds, // Insufficient Funds
'429': RateLimitExceeded, // Rate Limiting was applied
'500': ExchangeError, // The server encountered an error
- '502': ExchangeError, // Technical issues are preventing the request from being satisfied
+ '502': ExchangeNotAvailable, // Technical issues are preventing the request from being satisfied
'503': OnMaintenance, // The exchange is down for maintenance
},
'timeframes': {
@@ -154,10 +168,12 @@ module.exports = class gemini extends Exchange {
},
'broad': {
'The Gemini Exchange is currently undergoing maintenance.': OnMaintenance, // The Gemini Exchange is currently undergoing maintenance. Please check https://status.gemini.com/ for more information.
+ 'We are investigating technical issues with the Gemini Exchange.': ExchangeNotAvailable, // We are investigating technical issues with the Gemini Exchange. Please check https://status.gemini.com/ for more information.
},
},
'options': {
'fetchMarketsMethod': 'fetch_markets_from_web',
+ 'fetchTickerMethod': 'fetchTickerV1', // fetchTickerV1, fetchTickerV2, fetchTickerV1AndV2
},
});
}
@@ -167,7 +183,7 @@ module.exports = class gemini extends Exchange {
return await this[method] (params);
}
- async fetchMarketsFromWeb (symbols = undefined, params = {}) {
+ async fetchMarketsFromWeb (params = {}) {
const response = await this.webGetRestApi (params);
const sections = response.split ('Symbols and minimums
');
const numSections = sections.length;
@@ -191,73 +207,62 @@ module.exports = class gemini extends Exchange {
const row = rows[i];
const cells = row.split ("\n"); // eslint-disable-line quotes
const numCells = cells.length;
- if (numCells < 9) {
+ if (numCells < 5) {
throw new NotSupported (error);
}
// [
- // 'BTC', // currency
+ // ' | btcusd', // currency
// ' | 0.00001 BTC (1e-5)', // min order size
// ' | 0.00000001 BTC (1e-8)', // tick size
- // ' | 0.01 USD', // usd price increment
- // ' | N/A', // btc price increment
- // ' | 0.0001 ETH (1e-4)', // eth price increment
- // ' | 0.0001 BCH (1e-4)', // bch price increment
- // ' | 0.001 LTC (1e-3)', // ltc price increment
+ // ' | 0.01 USD', // quote currency price increment
// ''
// ]
- //
- const uppercaseBaseId = cells[0].replace (' | ', '');
- const baseId = uppercaseBaseId.toLowerCase ();
- const base = this.safeCurrencyCode (baseId);
- const quoteIds = [ 'usd', 'btc', 'eth', 'bch', 'ltc' ];
+ const marketId = cells[0].replace (' | ', '');
+ // const base = this.safeCurrencyCode (baseId);
const minAmountString = cells[1].replace (' | ', '');
const minAmountParts = minAmountString.split (' ');
const minAmount = this.safeFloat (minAmountParts, 0);
const amountPrecisionString = cells[2].replace (' | ', '');
const amountPrecisionParts = amountPrecisionString.split (' ');
- const amountPrecision = this.precisionFromString (amountPrecisionParts[0]);
- for (let j = 0; j < quoteIds.length; j++) {
- const quoteId = quoteIds[j];
- const quote = this.safeCurrencyCode (quoteId);
- const pricePrecisionIndex = this.sum (3, j);
- const pricePrecisionString = cells[pricePrecisionIndex].replace (' | ', '');
- if (pricePrecisionString === 'N/A') {
- continue;
- }
- const pricePrecisionParts = pricePrecisionString.split (' ');
- const pricePrecision = this.precisionFromString (pricePrecisionParts[0]);
- const symbol = base + '/' + quote;
- const id = baseId + quoteId;
- const active = undefined;
- result.push ({
- 'id': id,
- 'info': row,
- 'symbol': symbol,
- 'base': base,
- 'quote': quote,
- 'baseId': baseId,
- 'quoteId': quoteId,
- 'active': active,
- 'precision': {
- 'amount': amountPrecision,
- 'price': pricePrecision,
+ const amountPrecision = this.safeFloat (amountPrecisionParts, 0);
+ const idLength = marketId.length - 0;
+ const quoteId = marketId.slice (idLength - 3, idLength);
+ const quote = this.safeCurrencyCode (quoteId);
+ const pricePrecisionString = cells[3].replace (' | ', '');
+ const pricePrecisionParts = pricePrecisionString.split (' ');
+ const pricePrecision = this.safeFloat (pricePrecisionParts, 0);
+ const baseId = marketId.replace (quoteId, '');
+ const base = this.safeCurrencyCode (baseId);
+ const symbol = base + '/' + quote;
+ const active = undefined;
+ result.push ({
+ 'id': marketId,
+ 'info': row,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'active': active,
+ 'precision': {
+ 'amount': amountPrecision,
+ 'price': pricePrecision,
+ },
+ 'limits': {
+ 'amount': {
+ 'min': minAmount,
+ 'max': undefined,
},
- 'limits': {
- 'amount': {
- 'min': minAmount,
- 'max': undefined,
- },
- 'price': {
- 'min': undefined,
- 'max': undefined,
- },
- 'cost': {
- 'min': undefined,
- 'max': undefined,
- },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
},
- });
- }
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ });
}
return result;
}
@@ -266,10 +271,11 @@ module.exports = class gemini extends Exchange {
const response = await this.publicGetV1Symbols (params);
const result = [];
for (let i = 0; i < response.length; i++) {
- const id = response[i];
- const market = id;
- const baseId = id.slice (0, 3);
- const quoteId = id.slice (3, 6);
+ const marketId = response[i];
+ const market = marketId;
+ const idLength = marketId.length - 0;
+ const baseId = marketId.slice (0, idLength - 3);
+ const quoteId = marketId.slice (idLength - 3, idLength);
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
@@ -278,7 +284,7 @@ module.exports = class gemini extends Exchange {
'price': undefined,
};
result.push ({
- 'id': id,
+ 'id': marketId,
'info': market,
'symbol': symbol,
'base': base,
@@ -319,42 +325,229 @@ module.exports = class gemini extends Exchange {
return this.parseOrderBook (response, undefined, 'bids', 'asks', 'price', 'amount');
}
- async fetchTicker (symbol, params = {}) {
+ async fetchTickerV1 (symbol, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
'symbol': market['id'],
};
- const ticker = await this.publicGetV1PubtickerSymbol (this.extend (request, params));
- const timestamp = this.safeInteger (ticker['volume'], 'timestamp');
- const baseCurrency = market['base']; // unified structures are guaranteed to have unified fields
- const quoteCurrency = market['quote']; // so we don't need safe-methods for unified structures
- const last = this.safeFloat (ticker, 'last');
+ const response = await this.publicGetV1PubtickerSymbol (this.extend (request, params));
+ //
+ // {
+ // "bid":"9117.95",
+ // "ask":"9117.96",
+ // "volume":{
+ // "BTC":"1615.46861748",
+ // "USD":"14727307.57545006088",
+ // "timestamp":1594982700000
+ // },
+ // "last":"9115.23"
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ async fetchTickerV2 (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this.publicGetV2TickerSymbol (this.extend (request, params));
+ //
+ // {
+ // "symbol":"BTCUSD",
+ // "open":"9080.58",
+ // "high":"9184.53",
+ // "low":"9063.56",
+ // "close":"9116.08",
+ // // Hourly prices descending for past 24 hours
+ // "changes":["9117.33","9105.69","9106.23","9120.35","9098.57","9114.53","9113.55","9128.01","9113.63","9133.49","9133.49","9137.75","9126.73","9103.91","9119.33","9123.04","9124.44","9117.57","9114.22","9102.33","9076.67","9074.72","9074.97","9092.05"],
+ // "bid":"9115.86",
+ // "ask":"9115.87"
+ // }
+ //
+ return this.parseTicker (response, market);
+ }
+
+ async fetchTickerV1AndV2 (symbol, params = {}) {
+ const tickerA = await this.fetchTickerV1 (symbol, params);
+ const tickerB = await this.fetchTickerV2 (symbol, params);
+ return this.deepExtend (tickerA, {
+ 'open': tickerB['open'],
+ 'high': tickerB['high'],
+ 'low': tickerB['low'],
+ 'change': tickerB['change'],
+ 'percentage': tickerB['percentage'],
+ 'average': tickerB['average'],
+ 'info': tickerB['info'],
+ });
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ const method = this.safeValue (this.options, 'fetchTickerMethod', 'fetchTickerV1');
+ return await this[method] (symbol, params);
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTickers
+ //
+ // {
+ // "pair": "BATUSD",
+ // "price": "0.20687",
+ // "percentChange24h": "0.0146"
+ // }
+ //
+ // fetchTickerV1
+ //
+ // {
+ // "bid":"9117.95",
+ // "ask":"9117.96",
+ // "volume":{
+ // "BTC":"1615.46861748",
+ // "USD":"14727307.57545006088",
+ // "timestamp":1594982700000
+ // },
+ // "last":"9115.23"
+ // }
+ //
+ // fetchTickerV2
+ //
+ // {
+ // "symbol":"BTCUSD",
+ // "open":"9080.58",
+ // "high":"9184.53",
+ // "low":"9063.56",
+ // "close":"9116.08",
+ // // Hourly prices descending for past 24 hours
+ // "changes":["9117.33","9105.69","9106.23","9120.35","9098.57","9114.53","9113.55","9128.01","9113.63","9133.49","9133.49","9137.75","9126.73","9103.91","9119.33","9123.04","9124.44","9117.57","9114.22","9102.33","9076.67","9074.72","9074.97","9092.05"],
+ // "bid":"9115.86",
+ // "ask":"9115.87"
+ // }
+ //
+ const volume = this.safeValue (ticker, 'volume', {});
+ const timestamp = this.safeInteger (volume, 'timestamp');
+ let symbol = undefined;
+ const marketId = this.safeString (ticker, 'pair');
+ let baseId = undefined;
+ let quoteId = undefined;
+ let base = undefined;
+ let quote = undefined;
+ if (marketId !== undefined) {
+ if (marketId in this.markets_by_id) {
+ market = this.markets_by_id[marketId];
+ } else {
+ const idLength = marketId.length - 0;
+ if (idLength === 7) {
+ baseId = marketId.slice (0, 4);
+ quoteId = marketId.slice (4, 7);
+ } else {
+ baseId = marketId.slice (0, 3);
+ quoteId = marketId.slice (3, 6);
+ }
+ base = this.safeCurrencyCode (baseId);
+ quote = this.safeCurrencyCode (quoteId);
+ symbol = base + '/' + quote;
+ }
+ }
+ if ((symbol === undefined) && (market !== undefined)) {
+ symbol = market['symbol'];
+ baseId = market['baseId'].toUpperCase ();
+ quoteId = market['quoteId'].toUpperCase ();
+ base = market['base'];
+ quote = market['quote'];
+ }
+ const price = this.safeFloat (ticker, 'price');
+ const last = this.safeFloat2 (ticker, 'last', 'close', price);
+ let percentage = this.safeFloat (ticker, 'percentChange24h');
+ let change = undefined;
+ let open = this.safeFloat (ticker, 'open');
+ let average = undefined;
+ if (last !== undefined) {
+ if (open !== undefined) {
+ change = last - open;
+ if (open !== 0) {
+ percentage = change / open * 100;
+ }
+ average = this.sum (last, open) / 2;
+ } else if (percentage !== undefined) {
+ change = last * percentage;
+ if (open === undefined) {
+ open = last - change;
+ }
+ average = this.sum (last, open) / 2;
+ }
+ }
+ const baseVolume = this.safeFloat (volume, baseId);
+ const quoteVolume = this.safeFloat (volume, quoteId);
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
- 'high': undefined,
- 'low': undefined,
+ 'high': this.safeFloat (ticker, 'high'),
+ 'low': this.safeFloat (ticker, 'low'),
'bid': this.safeFloat (ticker, 'bid'),
'bidVolume': undefined,
'ask': this.safeFloat (ticker, 'ask'),
'askVolume': undefined,
- 'vwap': undefined,
- 'open': undefined,
+ 'vwap': vwap,
+ 'open': open,
'close': last,
'last': last,
- 'previousClose': undefined,
- 'change': undefined,
- 'percentage': undefined,
- 'average': undefined,
- 'baseVolume': this.safeFloat (ticker['volume'], baseCurrency),
- 'quoteVolume': this.safeFloat (ticker['volume'], quoteCurrency),
+ 'previousClose': undefined, // previous day close
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
'info': ticker,
};
}
+ parseTickers (tickers, symbols = undefined) {
+ const result = [];
+ for (let i = 0; i < tickers.length; i++) {
+ result.push (this.parseTicker (tickers[i]));
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetV1Pricefeed (params);
+ //
+ // [
+ // {
+ // "pair": "BATUSD",
+ // "price": "0.20687",
+ // "percentChange24h": "0.0146"
+ // },
+ // {
+ // "pair": "LINKETH",
+ // "price": "0.018",
+ // "percentChange24h": "0.0000"
+ // },
+ // ]
+ //
+ return this.parseTickers (response, symbols);
+ }
+
parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades
+ //
+ // {
+ // "timestamp":1601617445,
+ // "timestampms":1601617445144,
+ // "tid":14122489752,
+ // "price":"0.46476",
+ // "amount":"28.407209",
+ // "exchange":"gemini",
+ // "type":"buy"
+ // }
+ //
const timestamp = this.safeInteger (trade, 'timestampms');
const id = this.safeString (trade, 'tid');
const orderId = this.safeString (trade, 'order_id');
@@ -374,10 +567,7 @@ module.exports = class gemini extends Exchange {
}
const type = undefined;
const side = this.safeStringLower (trade, 'type');
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (undefined, market);
return {
'id': id,
'order': orderId,
@@ -402,6 +592,19 @@ module.exports = class gemini extends Exchange {
'symbol': market['id'],
};
const response = await this.publicGetV1TradesSymbol (this.extend (request, params));
+ //
+ // [
+ // {
+ // "timestamp":1601617445,
+ // "timestampms":1601617445144,
+ // "tid":14122489752,
+ // "price":"0.46476",
+ // "amount":"28.407209",
+ // "exchange":"gemini",
+ // "type":"buy"
+ // },
+ // ]
+ //
return this.parseTrades (response, market, since, limit);
}
@@ -450,16 +653,8 @@ module.exports = class gemini extends Exchange {
type = order['type'];
}
const fee = undefined;
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
const id = this.safeString (order, 'order_id');
const side = this.safeStringLower (order, 'side');
const clientOrderId = this.safeString (order, 'client_order_id');
@@ -473,8 +668,10 @@ module.exports = class gemini extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'average': average,
'cost': cost,
'amount': amount,
@@ -497,12 +694,11 @@ module.exports = class gemini extends Exchange {
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privatePostV1Orders (params);
- let orders = this.parseOrders (response, undefined, since, limit);
+ let market = undefined;
if (symbol !== undefined) {
- const market = this.market (symbol); // throws on non-existent symbol
- orders = this.filterBySymbol (orders, market['symbol']);
+ market = this.market (symbol); // throws on non-existent symbol
}
- return orders;
+ return this.parseOrders (response, market, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
@@ -633,7 +829,7 @@ module.exports = class gemini extends Exchange {
'nonce': nonce,
}, query);
let payload = this.json (request);
- payload = this.stringToBase64 (this.encode (payload));
+ payload = this.stringToBase64 (payload);
const signature = this.hmac (payload, this.encode (this.secret), 'sha384');
headers = {
'Content-Type': 'text/plain',
@@ -702,6 +898,13 @@ module.exports = class gemini extends Exchange {
'symbol': market['id'],
};
const response = await this.publicGetV2CandlesSymbolTimeframe (this.extend (request, params));
+ //
+ // [
+ // [1591515000000,0.02509,0.02509,0.02509,0.02509,0],
+ // [1591514700000,0.02503,0.02509,0.02503,0.02509,44.6405],
+ // [1591514400000,0.02503,0.02503,0.02503,0.02503,0],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
};
diff --git a/TaskServer/node_modules/ccxt/js/hbtc.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/hbtc.js
similarity index 98%
rename from TaskServer/node_modules/ccxt/js/hbtc.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/hbtc.js
index 317dc9d90..d7bde5c6c 100644
--- a/TaskServer/node_modules/ccxt/js/hbtc.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/hbtc.js
@@ -17,27 +17,32 @@ module.exports = class hbtc extends Exchange {
'rateLimit': 2000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchTime': true,
+ 'createOrder': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
'fetchBidAsk': true,
'fetchBidsAsks': true,
- 'fetchTickers': true,
- 'fetchTicker': true,
- 'fetchDepositAddress': false,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
'fetchClosedOrders': true,
- 'fetchTradingLimits': true,
+ 'fetchCurrencies': false,
+ 'fetchDepositAddress': false,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
'fetchMarkets': true,
'fetchMyTrades': true,
- 'withdraw': true,
- 'fetchCurrencies': false,
- 'fetchDeposits': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchTradingLimits': true,
'fetchWithdrawals': true,
- 'fetchAccounts': true,
- 'fetchLedger': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1m',
@@ -177,8 +182,8 @@ module.exports = class hbtc extends Exchange {
'trading': {
'tierBased': false,
'percentage': true,
- 'maker': 0.002, // MAKER费率
- 'taker': 0.002, // TAKER费率
+ 'maker': 0.001,
+ 'taker': 0.001,
},
},
'exceptions': {
@@ -751,7 +756,7 @@ module.exports = class hbtc extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// [
// 1587906000000, // open time
@@ -1659,14 +1664,8 @@ module.exports = class hbtc extends Exchange {
// "askQty": "9.00000000"
// }
//
- let symbol = undefined;
const marketId = this.safeString (ticker, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.safeInteger (ticker, 'time');
const open = this.safeFloat (ticker, 'openPrice');
const close = this.safeFloat (ticker, 'lastPrice');
@@ -1682,10 +1681,7 @@ module.exports = class hbtc extends Exchange {
}
const quoteVolume = this.safeFloat (ticker, 'quoteVolume');
const baseVolume = this.safeFloat (ticker, 'volume');
- let vwap = undefined;
- if (baseVolume !== undefined && quoteVolume !== undefined && baseVolume > 0) {
- vwap = quoteVolume / baseVolume;
- }
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -1871,16 +1867,8 @@ module.exports = class hbtc extends Exchange {
if (timestamp === undefined) {
timestamp = this.safeInteger (order, 'transactTime');
}
- let symbol = undefined;
- if (market === undefined) {
- let marketId = this.safeString (order, 'symbol');
- if (marketId !== undefined) {
- marketId = marketId.toUpperCase ();
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
let type = this.safeStringLower (order, 'type');
const side = this.safeStringLower (order, 'side');
let price = this.safeFloat (order, 'price');
@@ -1917,9 +1905,8 @@ module.exports = class hbtc extends Exchange {
average = undefined;
}
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const timeInForce = this.safeString (order, 'timeInForce');
+ const stopPrice = this.safeFloat (order, 'stopPrice');
const result = {
'info': order,
'id': id,
@@ -1929,8 +1916,10 @@ module.exports = class hbtc extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'average': average,
'cost': cost,
'amount': amount,
diff --git a/TaskServer/node_modules/ccxt/js/hitbtc.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/hitbtc.js
similarity index 68%
rename from TaskServer/node_modules/ccxt/js/hitbtc.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/hitbtc.js
index 14b6e46a0..0ec19ca80 100644
--- a/TaskServer/node_modules/ccxt/js/hitbtc.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/hitbtc.js
@@ -4,7 +4,8 @@
const Exchange = require ('./base/Exchange');
const { BadSymbol, PermissionDenied, ExchangeError, ExchangeNotAvailable, OrderNotFound, InsufficientFunds, InvalidOrder, RequestTimeout, AuthenticationError } = require ('./base/errors');
-const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number');
+const { TRUNCATE, DECIMAL_PLACES, TICK_SIZE } = require ('./base/functions/number');
+
// ---------------------------------------------------------------------------
module.exports = class hitbtc extends Exchange {
@@ -17,24 +18,32 @@ module.exports = class hitbtc extends Exchange {
'version': '2',
'pro': true,
'has': {
- 'createDepositAddress': true,
- 'fetchDepositAddress': true,
+ 'cancelOrder': true,
'CORS': false,
+ 'createDepositAddress': true,
+ 'createOrder': true,
'editOrder': true,
- 'fetchCurrencies': true,
- 'fetchOHLCV': true,
- 'fetchTickers': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchMyTrades': true,
- 'withdraw': true,
- 'fetchOrderTrades': false, // not implemented yet
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
'fetchDeposits': false,
- 'fetchWithdrawals': false,
- 'fetchTransactions': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrder': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchOrderTrades': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
+ 'fetchTransactions': true,
+ 'fetchWithdrawals': false,
+ 'withdraw': true,
},
'timeframes': {
'1m': 'M1',
@@ -74,46 +83,61 @@ module.exports = class hitbtc extends Exchange {
'currency/{currency}', // Get currency info
'ticker', // Ticker list for all symbols
'ticker/{symbol}', // Ticker for symbol
+ 'trades',
'trades/{symbol}', // Trades
+ 'orderbook',
'orderbook/{symbol}', // Orderbook
+ 'candles',
'candles/{symbol}', // Candles
],
},
'private': {
'get': [
+ 'trading/balance', // Get trading balance
'order', // List your current open orders
'order/{clientOrderId}', // Get a single order by clientOrderId
- 'trading/balance', // Get trading balance
'trading/fee/all', // Get trading fee rate
'trading/fee/{symbol}', // Get trading fee rate
- 'history/trades', // Get historical trades
'history/order', // Get historical orders
- 'history/order/{id}/trades', // Get historical trades by specified order
+ 'history/trades', // Get historical trades
+ 'history/order/{orderId}/trades', // Get historical trades by specified order
'account/balance', // Get main acccount balance
+ 'account/crypto/address/{currency}', // Get deposit crypro address
+ 'account/crypto/is-mine/{address}',
'account/transactions', // Get account transactions
'account/transactions/{id}', // Get account transaction by id
- 'account/crypto/address/{currency}', // Get deposit crypro address
+ 'sub-acc',
+ 'sub-acc/acl',
+ 'sub-acc/balance/{subAccountUserID}',
+ 'sub-acc/deposit-address/{subAccountUserId}/{currency}',
],
'post': [
'order', // Create new order
- 'account/crypto/withdraw', // Withdraw crypro
'account/crypto/address/{currency}', // Create new deposit crypro address
+ 'account/crypto/withdraw', // Withdraw crypro
+ 'account/crypto/transfer-convert',
'account/transfer', // Transfer amount to trading
+ 'sub-acc/freeze',
+ 'sub-acc/activate',
+ 'sub-acc/transfer',
],
'put': [
'order/{clientOrderId}', // Create new order
'account/crypto/withdraw/{id}', // Commit withdraw crypro
+ 'sub-acc/acl/{subAccountUserId}',
],
'delete': [
'order', // Cancel all open orders
'order/{clientOrderId}', // Cancel order
'account/crypto/withdraw/{id}', // Rollback withdraw crypro
],
+ // outdated?
'patch': [
'order/{clientOrderId}', // Cancel Replace order
],
},
},
+ 'precisionMode': TICK_SIZE,
'fees': {
'trading': {
'tierBased': false,
@@ -121,444 +145,24 @@ module.exports = class hitbtc extends Exchange {
'maker': 0.1 / 100,
'taker': 0.2 / 100,
},
- 'funding': {
- 'tierBased': false,
- 'percentage': false,
- 'withdraw': {
- 'BTC': 0.001,
- 'BCC': 0.0018,
- 'ETH': 0.00958,
- 'BCH': 0.0018,
- 'USDT': 100,
- 'DASH': 0.03,
- 'BTG': 0.0005,
- 'XRP': 0.509,
- 'LTC': 0.003,
- 'ZEC': 0.0001,
- 'XMR': 0.09,
- '1ST': 0.84,
- 'ADX': 5.7,
- 'AE': 6.7,
- 'AEON': 0.01006,
- 'AIR': 565,
- 'AMM': 14,
- 'AMP': 342,
- 'ANT': 6.7,
- 'ARDR': 1,
- 'ARN': 18.5,
- 'ART': 26,
- 'ATB': 0.0004,
- 'ATL': 27,
- 'ATM': 504,
- 'ATS': 860,
- 'AVT': 1.9,
- 'BAS': 113,
- 'BCN': 0.1,
- 'BET': 124,
- 'BKB': 46,
- 'BMC': 32,
- 'BMT': 100,
- 'BNT': 2.57,
- 'BQX': 4.7,
- 'BTCA': 351.21,
- 'BTM': 40,
- 'BTX': 0.04,
- 'BUS': 0.004,
- 'CAPP': 97,
- 'CCT': 6,
- 'CDT': 100,
- 'CDX': 30,
- 'CFI': 61,
- 'CL': 13.85,
- 'CLD': 0.88,
- 'CND': 574,
- 'CNX': 0.04,
- 'COSS': 65,
- 'CPAY': 5.487,
- 'CSNO': 16,
- 'CTR': 15,
- 'CTX': 146,
- 'CVC': 8.46,
- 'DATA': 12.949,
- 'DBIX': 0.0168,
- 'DCN': 1280,
- 'DCT': 0.02,
- 'DDF': 342,
- 'DENT': 1000,
- 'DGB': 0.4,
- 'DGD': 0.01,
- 'DICE': 0.32,
- 'DLT': 0.26,
- 'DNT': 0.21,
- 'DOGE': 2,
- 'DOV': 34,
- 'DRPU': 24,
- 'DRT': 240,
- 'DSH': 0.017,
- 'EBET': 84,
- 'EBTC': 20,
- 'EBTCOLD': 6.6,
- 'ECAT': 14,
- 'EDG': 2,
- 'EDO': 2.9,
- 'EKO': 1136.36,
- 'ELE': 0.00172,
- 'ELM': 0.004,
- 'EMC': 0.03,
- 'MGO': 14,
- 'ENJ': 163,
- 'EOS': 1.5,
- 'ERO': 34,
- 'ETBS': 15,
- 'ETC': 0.002,
- 'ETP': 0.004,
- 'EVX': 5.4,
- 'EXN': 456,
- 'FCN': 0.000005,
- 'FRD': 65,
- 'FUEL': 123.00105,
- 'FUN': 202.9598309,
- 'FYN': 1.849,
- 'FYP': 66.13,
- 'GAME': 0.004,
- 'GNO': 0.0034,
- 'GUP': 4,
- 'GVT': 1.2,
- 'HSR': 0.04,
- 'HAC': 144,
- 'HDG': 7,
- 'HGT': 1082,
- 'HPC': 0.4,
- 'HVN': 120,
- 'ICN': 0.55,
- 'ICO': 34,
- 'ICOS': 0.35,
- 'IND': 76,
- 'INDI': 790,
- 'ITS': 15.0012,
- 'IXT': 11,
- 'KBR': 143,
- 'KICK': 112,
- 'KMD': 4,
- 'LA': 41,
- 'LEND': 388,
- 'LAT': 1.44,
- 'LIFE': 13000,
- 'LRC': 27,
- 'LSK': 0.3,
- 'LOC': 11.076,
- 'LUN': 0.34,
- 'MAID': 5,
- 'MANA': 143,
- 'MCAP': 5.44,
- 'MIPS': 43,
- 'MNE': 1.33,
- 'MSP': 121,
- 'MCO': 0.357,
- 'MTH': 92,
- 'MYB': 3.9,
- 'NDC': 165,
- 'NEBL': 0.04,
- 'NET': 3.96,
- 'NTO': 998,
- 'NGC': 2.368,
- 'NXC': 13.39,
- 'NXT': 3,
- 'OAX': 15,
- 'ODN': 0.004,
- 'OMG': 2,
- 'OPT': 335,
- 'ORME': 2.8,
- 'OTN': 0.57,
- 'PAY': 3.1,
- 'PIX': 96,
- 'PLBT': 0.33,
- 'PLR': 114,
- 'PLU': 0.87,
- 'POE': 784,
- 'POLL': 3.5,
- 'PPT': 2,
- 'PRE': 32,
- 'PRG': 39,
- 'PRO': 41,
- 'PRS': 60,
- 'PTOY': 0.5,
- 'QAU': 63,
- 'QCN': 0.03,
- 'QTUM': 0.04,
- 'QVT': 64,
- 'REP': 0.02,
- 'RKC': 15,
- 'RLC': 1.21,
- 'RVT': 14,
- 'SC': 30,
- 'SAN': 2.24,
- 'SBD': 0.03,
- 'SCL': 2.6,
- 'SISA': 1640,
- 'SKIN': 407,
- 'SWFTC': 352.94,
- 'SMART': 0.4,
- 'SMS': 0.0375,
- 'SNC': 36,
- 'SNGLS': 4,
- 'SNM': 48,
- 'SNT': 233,
- 'STAR': 0.144,
- 'STORM': 153.19,
- 'STEEM': 0.01,
- 'STRAT': 0.01,
- 'SPF': 14.4,
- 'STU': 14,
- 'STX': 11,
- 'SUB': 17,
- 'SUR': 3,
- 'SWT': 0.51,
- 'TAAS': 0.91,
- 'TBT': 2.37,
- 'TFL': 15,
- 'TIME': 0.03,
- 'TIX': 7.1,
- 'TKN': 1,
- 'TGT': 173,
- 'TKR': 84,
- 'TNT': 90,
- 'TRST': 1.6,
- 'TRX': 270,
- 'UET': 480,
- 'UGT': 15,
- 'UTT': 3,
- 'VEN': 14,
- 'VERI': 0.037,
- 'VIB': 50,
- 'VIBE': 145,
- 'VOISE': 618,
- 'WEALTH': 0.0168,
- 'WINGS': 2.4,
- 'WTC': 0.75,
- 'WRC': 48,
- 'XAUR': 3.23,
- 'XDN': 0.01,
- 'XEM': 15,
- 'XUC': 0.9,
- 'YOYOW': 140,
- 'ZAP': 24,
- 'ZRX': 23,
- 'ZSC': 191,
- },
- 'deposit': {
- 'BTC': 0,
- 'ETH': 0,
- 'BCH': 0,
- 'USDT': 0,
- 'BTG': 0,
- 'LTC': 0,
- 'ZEC': 0,
- 'XMR': 0,
- '1ST': 0,
- 'ADX': 0,
- 'AE': 0,
- 'AEON': 0,
- 'AIR': 0,
- 'AMP': 0,
- 'ANT': 0,
- 'ARDR': 0,
- 'ARN': 0,
- 'ART': 0,
- 'ATB': 0,
- 'ATL': 0,
- 'ATM': 0,
- 'ATS': 0,
- 'AVT': 0,
- 'BAS': 0,
- 'BCN': 0,
- 'BET': 0,
- 'BKB': 0,
- 'BMC': 0,
- 'BMT': 0,
- 'BNT': 0,
- 'BQX': 0,
- 'BTM': 0,
- 'BTX': 0,
- 'BUS': 0,
- 'CCT': 0,
- 'CDT': 0,
- 'CDX': 0,
- 'CFI': 0,
- 'CLD': 0,
- 'CND': 0,
- 'CNX': 0,
- 'COSS': 0,
- 'CSNO': 0,
- 'CTR': 0,
- 'CTX': 0,
- 'CVC': 0,
- 'DBIX': 0,
- 'DCN': 0,
- 'DCT': 0,
- 'DDF': 0,
- 'DENT': 0,
- 'DGB': 0,
- 'DGD': 0,
- 'DICE': 0,
- 'DLT': 0,
- 'DNT': 0,
- 'DOGE': 0,
- 'DOV': 0,
- 'DRPU': 0,
- 'DRT': 0,
- 'DSH': 0,
- 'EBET': 0,
- 'EBTC': 0,
- 'EBTCOLD': 0,
- 'ECAT': 0,
- 'EDG': 0,
- 'EDO': 0,
- 'ELE': 0,
- 'ELM': 0,
- 'EMC': 0,
- 'EMGO': 0,
- 'ENJ': 0,
- 'EOS': 0,
- 'ERO': 0,
- 'ETBS': 0,
- 'ETC': 0,
- 'ETP': 0,
- 'EVX': 0,
- 'EXN': 0,
- 'FRD': 0,
- 'FUEL': 0,
- 'FUN': 0,
- 'FYN': 0,
- 'FYP': 0,
- 'GNO': 0,
- 'GUP': 0,
- 'GVT': 0,
- 'HAC': 0,
- 'HDG': 0,
- 'HGT': 0,
- 'HPC': 0,
- 'HVN': 0,
- 'ICN': 0,
- 'ICO': 0,
- 'ICOS': 0,
- 'IND': 0,
- 'INDI': 0,
- 'ITS': 0,
- 'IXT': 0,
- 'KBR': 0,
- 'KICK': 0,
- 'LA': 0,
- 'LAT': 0,
- 'LIFE': 0,
- 'LRC': 0,
- 'LSK': 0,
- 'LUN': 0,
- 'MAID': 0,
- 'MANA': 0,
- 'MCAP': 0,
- 'MIPS': 0,
- 'MNE': 0,
- 'MSP': 0,
- 'MTH': 0,
- 'MYB': 0,
- 'NDC': 0,
- 'NEBL': 0,
- 'NET': 0,
- 'NTO': 0,
- 'NXC': 0,
- 'NXT': 0,
- 'OAX': 0,
- 'ODN': 0,
- 'OMG': 0,
- 'OPT': 0,
- 'ORME': 0,
- 'OTN': 0,
- 'PAY': 0,
- 'PIX': 0,
- 'PLBT': 0,
- 'PLR': 0,
- 'PLU': 0,
- 'POE': 0,
- 'POLL': 0,
- 'PPT': 0,
- 'PRE': 0,
- 'PRG': 0,
- 'PRO': 0,
- 'PRS': 0,
- 'PTOY': 0,
- 'QAU': 0,
- 'QCN': 0,
- 'QTUM': 0,
- 'QVT': 0,
- 'REP': 0,
- 'RKC': 0,
- 'RVT': 0,
- 'SAN': 0,
- 'SBD': 0,
- 'SCL': 0,
- 'SISA': 0,
- 'SKIN': 0,
- 'SMART': 0,
- 'SMS': 0,
- 'SNC': 0,
- 'SNGLS': 0,
- 'SNM': 0,
- 'SNT': 0,
- 'STEEM': 0,
- 'STRAT': 0,
- 'STU': 0,
- 'STX': 0,
- 'SUB': 0,
- 'SUR': 0,
- 'SWT': 0,
- 'TAAS': 0,
- 'TBT': 0,
- 'TFL': 0,
- 'TIME': 0,
- 'TIX': 0,
- 'TKN': 0,
- 'TKR': 0,
- 'TNT': 0,
- 'TRST': 0,
- 'TRX': 0,
- 'UET': 0,
- 'UGT': 0,
- 'VEN': 0,
- 'VERI': 0,
- 'VIB': 0,
- 'VIBE': 0,
- 'VOISE': 0,
- 'WEALTH': 0,
- 'WINGS': 0,
- 'WTC': 0,
- 'XAUR': 0,
- 'XDN': 0,
- 'XEM': 0,
- 'XUC': 0,
- 'YOYOW': 0,
- 'ZAP': 0,
- 'ZRX': 0,
- 'ZSC': 0,
- },
- },
},
'options': {
'defaultTimeInForce': 'FOK',
},
'commonCurrencies': {
+ 'BCC': 'BCC', // initial symbol for Bitcoin Cash, now inactive
'BET': 'DAO.Casino',
- 'CAT': 'BitClave',
+ 'BOX': 'BOX Token',
'CPT': 'Cryptaur', // conflict with CPT = Contents Protocol https://github.com/ccxt/ccxt/issues/4920 and https://github.com/ccxt/ccxt/issues/6081
- 'DRK': 'DASH',
- 'EMGO': 'MGO',
'GET': 'Themis',
'HSR': 'HC',
+ 'IQ': 'IQ.Cash',
'LNC': 'LinkerCoin',
'PLA': 'PlayChip',
- 'UNC': 'Unigame',
+ 'PNT': 'Penta',
+ 'TV': 'Tokenville',
'USD': 'USDT',
- 'XBT': 'BTC',
+ 'XPNT': 'PNT',
},
'exceptions': {
'504': RequestTimeout, // {"error":{"code":504,"message":"Gateway Timeout"}}
@@ -569,8 +173,9 @@ module.exports = class hitbtc extends Exchange {
'2011': InvalidOrder, // "Quantity too low"
'2020': InvalidOrder, // "Price not a valid number"
'20002': OrderNotFound, // canceling non-existent order
- '20001': InsufficientFunds,
+ '20001': InsufficientFunds, // {"error":{"code":20001,"message":"Insufficient funds","description":"Check that the funds are sufficient, given commissions"}}
},
+ 'orders': {}, // orders cache / emulation
});
}
@@ -580,6 +185,20 @@ module.exports = class hitbtc extends Exchange {
async fetchMarkets (params = {}) {
const response = await this.publicGetSymbol (params);
+ //
+ // [
+ // {
+ // "id":"BCNBTC",
+ // "baseCurrency":"BCN",
+ // "quoteCurrency":"BTC",
+ // "quantityIncrement":"100",
+ // "tickSize":"0.00000000001",
+ // "takeLiquidityRate":"0.002",
+ // "provideLiquidityRate":"0.001",
+ // "feeCurrency":"BTC"
+ // }
+ // ]
+ //
const result = [];
for (let i = 0; i < response.length; i++) {
const market = response[i];
@@ -588,17 +207,21 @@ module.exports = class hitbtc extends Exchange {
const quoteId = this.safeString (market, 'quoteCurrency');
const base = this.safeCurrencyCode (baseId);
const quote = this.safeCurrencyCode (quoteId);
- const symbol = base + '/' + quote;
+ let symbol = base + '/' + quote;
+ // bequant fix
+ if (id.indexOf ('_') >= 0) {
+ symbol = id;
+ }
const lot = this.safeFloat (market, 'quantityIncrement');
const step = this.safeFloat (market, 'tickSize');
const precision = {
- 'price': this.precisionFromString (market['tickSize']),
- // FIXME: for lots > 1 the following line returns 0
- // 'amount': this.precisionFromString (market['quantityIncrement']),
- 'amount': -1 * parseInt (Math.log10 (lot)),
+ 'price': step,
+ 'amount': lot,
};
const taker = this.safeFloat (market, 'takeLiquidityRate');
const maker = this.safeFloat (market, 'provideLiquidityRate');
+ const feeCurrencyId = this.safeString (market, 'feeCurrency');
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
result.push (this.extend (this.fees['trading'], {
'info': market,
'id': id,
@@ -611,6 +234,7 @@ module.exports = class hitbtc extends Exchange {
'taker': taker,
'maker': maker,
'precision': precision,
+ 'feeCurrency': feeCurrencyCode,
'limits': {
'amount': {
'min': lot,
@@ -632,6 +256,25 @@ module.exports = class hitbtc extends Exchange {
async fetchCurrencies (params = {}) {
const response = await this.publicGetCurrency (params);
+ //
+ // [
+ // {
+ // "id":"XPNT",
+ // "fullName":"pToken",
+ // "crypto":true,
+ // "payinEnabled":true,
+ // "payinPaymentId":false,
+ // "payinConfirmations":9,
+ // "payoutEnabled":true,
+ // "payoutIsPaymentId":false,
+ // "transferEnabled":true,
+ // "delisted":false,
+ // "payoutFee":"26.510000000000",
+ // "precisionPayout":18,
+ // "precisionTransfer":8
+ // }
+ // ]
+ //
const result = {};
for (let i = 0; i < response.length; i++) {
const currency = response[i];
@@ -639,7 +282,8 @@ module.exports = class hitbtc extends Exchange {
// todo: will need to rethink the fees
// to add support for multiple withdrawal/deposit methods and
// differentiated fees for each particular method
- const precision = 8; // default precision, todo: fix "magic constants"
+ const decimals = this.safeInteger (currency, 'precisionTransfer', 8);
+ const precision = 1 / Math.pow (10, decimals);
const code = this.safeCurrencyCode (id);
const payin = this.safeValue (currency, 'payinEnabled');
const payout = this.safeValue (currency, 'payoutEnabled');
@@ -669,12 +313,12 @@ module.exports = class hitbtc extends Exchange {
'precision': precision,
'limits': {
'amount': {
- 'min': Math.pow (10, -precision),
- 'max': Math.pow (10, precision),
+ 'min': 1 / Math.pow (10, decimals),
+ 'max': Math.pow (10, decimals),
},
'price': {
- 'min': Math.pow (10, -precision),
- 'max': Math.pow (10, precision),
+ 'min': 1 / Math.pow (10, decimals),
+ 'max': Math.pow (10, decimals),
},
'cost': {
'min': undefined,
@@ -729,7 +373,18 @@ module.exports = class hitbtc extends Exchange {
return this.parseBalance (result);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1d', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "timestamp":"2015-08-20T19:01:00.000Z",
+ // "open":"0.006",
+ // "close":"0.006",
+ // "min":"0.006",
+ // "max":"0.006",
+ // "volume":"0.003",
+ // "volumeQuote":"0.000018"
+ // }
+ //
return [
this.parse8601 (this.safeString (ohlcv, 'timestamp')),
this.safeFloat (ohlcv, 'open'),
@@ -754,6 +409,13 @@ module.exports = class hitbtc extends Exchange {
request['limit'] = limit;
}
const response = await this.publicGetCandlesSymbol (this.extend (request, params));
+ //
+ // [
+ // {"timestamp":"2015-08-20T19:01:00.000Z","open":"0.006","close":"0.006","min":"0.006","max":"0.006","volume":"0.003","volumeQuote":"0.000018"},
+ // {"timestamp":"2015-08-20T19:03:00.000Z","open":"0.006","close":"0.006","min":"0.006","max":"0.006","volume":"0.013","volumeQuote":"0.000078"},
+ // {"timestamp":"2015-08-20T19:06:00.000Z","open":"0.0055","close":"0.005","min":"0.005","max":"0.0055","volume":"0.003","volumeQuote":"0.0000155"},
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -789,14 +451,7 @@ module.exports = class hitbtc extends Exchange {
percentage = change / open * 100;
}
}
- let vwap = undefined;
- if (quoteVolume !== undefined) {
- if (baseVolume !== undefined) {
- if (baseVolume > 0) {
- vwap = quoteVolume / baseVolume;
- }
- }
- }
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -828,17 +483,11 @@ module.exports = class hitbtc extends Exchange {
for (let i = 0; i < response.length; i++) {
const ticker = response[i];
const marketId = this.safeString (ticker, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- const market = this.markets_by_id[marketId];
- const symbol = market['symbol'];
- result[symbol] = this.parseTicker (ticker, market);
- } else {
- result[marketId] = this.parseTicker (ticker);
- }
- }
+ const market = this.safeMarket (marketId);
+ const symbol = market['symbol'];
+ result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -855,7 +504,6 @@ module.exports = class hitbtc extends Exchange {
}
parseTrade (trade, market = undefined) {
- //
// createMarketOrder
//
// { fee: "0.0004644",
@@ -864,36 +512,39 @@ module.exports = class hitbtc extends Exchange {
// quantity: "1",
// timestamp: "2018-10-25T16:41:44.780Z" }
//
- // fetchTrades ...
+ // fetchTrades
//
- // fetchMyTrades ...
+ // { id: 974786185,
+ // price: '0.032462',
+ // quantity: '0.3673',
+ // side: 'buy',
+ // timestamp: '2020-10-16T12:57:39.846Z' }
//
+ // fetchMyTrades
+ //
+ // { id: 277210397,
+ // clientOrderId: '6e102f3e7f3f4e04aeeb1cdc95592f1a',
+ // orderId: 28102855393,
+ // symbol: 'ETHBTC',
+ // side: 'sell',
+ // quantity: '0.002',
+ // price: '0.073365',
+ // fee: '0.000000147',
+ // timestamp: '2018-04-28T18:39:55.345Z' }
const timestamp = this.parse8601 (trade['timestamp']);
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
let fee = undefined;
const feeCost = this.safeFloat (trade, 'fee');
if (feeCost !== undefined) {
- const feeCurrency = market ? market['quote'] : undefined;
+ const feeCurrencyCode = market ? market['feeCurrency'] : undefined;
fee = {
'cost': feeCost,
- 'currency': feeCurrency,
+ 'currency': feeCurrencyCode,
};
}
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
const orderId = this.safeString (trade, 'clientOrderId');
@@ -1065,7 +716,7 @@ module.exports = class hitbtc extends Exchange {
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
// their max accepted length is 32 characters
@@ -1091,14 +742,12 @@ module.exports = class hitbtc extends Exchange {
if (order['status'] === 'rejected') {
throw new InvalidOrder (this.id + ' order was rejected by the exchange ' + this.json (order));
}
- const id = order['id'];
- this.orders[id] = order;
return order;
}
async editOrder (id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
await this.loadMarkets ();
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
// their max accepted length is 32 characters
@@ -1117,14 +766,12 @@ module.exports = class hitbtc extends Exchange {
request['price'] = this.priceToPrecision (symbol, price);
}
const response = await this.privatePatchOrderClientOrderId (this.extend (request, params));
- const order = this.parseOrder (response);
- this.orders[order['id']] = order;
- return order;
+ return this.parseOrder (response);
}
async cancelOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
const request = {
@@ -1170,34 +817,17 @@ module.exports = class hitbtc extends Exchange {
const created = this.parse8601 (this.safeString (order, 'createdAt'));
const updated = this.parse8601 (this.safeString (order, 'updatedAt'));
const marketId = this.safeString (order, 'symbol');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['id'];
- }
- }
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
const amount = this.safeFloat (order, 'quantity');
const filled = this.safeFloat (order, 'cumQuantity');
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
const id = this.safeString (order, 'clientOrderId');
const clientOrderId = id;
let price = this.safeFloat (order, 'price');
- if (price === undefined) {
- if (id in this.orders) {
- price = this.orders[id]['price'];
- }
- }
let remaining = undefined;
let cost = undefined;
if (amount !== undefined) {
@@ -1245,6 +875,7 @@ module.exports = class hitbtc extends Exchange {
};
}
}
+ const timeInForce = this.safeString (order, 'timeInForce');
return {
'id': id,
'clientOrderId': clientOrderId, // https://github.com/ccxt/ccxt/issues/5674
@@ -1254,8 +885,10 @@ module.exports = class hitbtc extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'average': average,
'amount': amount,
'cost': cost,
@@ -1269,7 +902,7 @@ module.exports = class hitbtc extends Exchange {
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
const request = {
@@ -1285,7 +918,7 @@ module.exports = class hitbtc extends Exchange {
async fetchOpenOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
- // we use clientOrderId as the order id with HitBTC intentionally
+ // we use clientOrderId as the order id with this exchange intentionally
// because most of their endpoints will require clientOrderId
// explained here: https://github.com/ccxt/ccxt/issues/5674
const request = {
@@ -1396,9 +1029,9 @@ module.exports = class hitbtc extends Exchange {
market = this.market (symbol);
}
const request = {
- 'id': id,
+ 'orderId': id,
};
- const response = await this.privateGetHistoryOrderIdTrades (this.extend (request, params));
+ const response = await this.privateGetHistoryOrderOrderIdTrades (this.extend (request, params));
const numOrders = response.length;
if (numOrders > 0) {
return this.parseTrades (response, market, since, limit);
diff --git a/TaskServer/node_modules/ccxt/js/hollaex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/hollaex.js
similarity index 93%
rename from TaskServer/node_modules/ccxt/js/hollaex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/hollaex.js
index a4d080c94..47b127d50 100644
--- a/TaskServer/node_modules/ccxt/js/hollaex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/hollaex.js
@@ -273,16 +273,7 @@ module.exports = class hollaex extends Exchange {
for (let i = 0; i < marketIds.length; i++) {
const marketId = marketIds[i];
const orderbook = response[marketId];
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- const market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ const symbol = this.safeSymbol (marketId, undefined, '-');
const timestamp = this.parse8601 (this.safeString (orderbook, 'timestamp'));
result[symbol] = this.parseOrderBook (response[marketId], timestamp);
}
@@ -368,18 +359,9 @@ module.exports = class hollaex extends Exchange {
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
const ticker = response[key];
- let symbol = key;
- let market = undefined;
const marketId = this.safeString (ticker, 'symbol', key);
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
+ const market = this.safeMarket (marketId, undefined, '-');
+ const symbol = market['symbol'];
result[symbol] = this.parseTicker (ticker, market);
}
return this.filterByArray (result, 'symbol', symbols);
@@ -412,22 +394,8 @@ module.exports = class hollaex extends Exchange {
// "symbol": "bch-usdt"
// }
//
- let symbol = undefined;
const marketId = this.safeString (ticker, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const timestamp = this.parse8601 (this.safeString2 (ticker, 'time', 'timestamp'));
const close = this.safeFloat (ticker, 'close');
const result = {
@@ -475,7 +443,7 @@ module.exports = class hollaex extends Exchange {
// ]
// }
//
- const trades = await this.safeValue (response, market['id'], []);
+ const trades = this.safeValue (response, market['id'], []);
return this.parseTrades (trades, market, since, limit);
}
@@ -501,23 +469,9 @@ module.exports = class hollaex extends Exchange {
// "fee": 0.1
// }
//
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- let quote = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ market = this.safeMarket (marketId, market, '-');
+ const symbol = market['symbol'];
const datetime = this.safeString (trade, 'timestamp');
const timestamp = this.parse8601 (datetime);
const side = this.safeString (trade, 'side');
@@ -532,13 +486,14 @@ module.exports = class hollaex extends Exchange {
const feeCost = this.safeFloat (trade, 'fee');
let fee = undefined;
if (feeCost !== undefined) {
+ const quote = market['quote'];
const feeCurrencyCode = (market !== undefined) ? market['quote'] : quote;
fee = {
'cost': feeCost,
'currency': feeCurrencyCode,
};
}
- const result = {
+ return {
'info': trade,
'id': undefined,
'timestamp': timestamp,
@@ -553,7 +508,6 @@ module.exports = class hollaex extends Exchange {
'cost': cost,
'fee': fee,
};
- return result;
}
async fetchOHLCV (symbol, timeframe = '1h', since = undefined, limit = undefined, params = {}) {
@@ -718,22 +672,8 @@ module.exports = class hollaex extends Exchange {
// "filled":0
// }
//
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const id = this.safeString (order, 'id');
const timestamp = this.parse8601 (this.safeString (order, 'created_at'));
const type = this.safeString (order, 'type');
@@ -761,8 +701,10 @@ module.exports = class hollaex extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': filled,
'remaining': remaining,
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/huobijp.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/huobijp.js
new file mode 100644
index 000000000..45fafe606
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/huobijp.js
@@ -0,0 +1,39 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const huobipro = require ('./huobipro.js');
+const { NotSupported } = require ('./base/errors');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class huobijp extends huobipro {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'huobijp',
+ 'name': 'Huobi Japan',
+ 'countries': [ 'JP' ],
+ 'hostname': 'api-cloud.huobi.co.jp',
+ 'pro': true,
+ 'has': {
+ 'fetchDepositAddress': false,
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/85734211-85755480-b705-11ea-8b35-0b7f1db33a2f.jpg',
+ 'api': {
+ 'market': 'https://{hostname}',
+ 'public': 'https://{hostname}',
+ 'private': 'https://{hostname}',
+ },
+ 'www': 'https://www.huobi.co.jp',
+ 'referral': 'https://www.huobi.co.jp/register/?invite_code=znnq3',
+ 'doc': 'https://api-doc.huobi.co.jp',
+ 'fees': 'https://www.huobi.co.jp/support/fee',
+ },
+ });
+ }
+
+ async fetchDepositAddress (code, params = {}) {
+ throw new NotSupported (this.id + ' fetchDepositAddress not supported yet');
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/huobipro.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/huobipro.js
similarity index 88%
rename from TaskServer/node_modules/ccxt/js/huobipro.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/huobipro.js
index 497cdf9bf..62edb18d3 100644
--- a/TaskServer/node_modules/ccxt/js/huobipro.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/huobipro.js
@@ -3,7 +3,8 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { AuthenticationError, ExchangeError, PermissionDenied, ExchangeNotAvailable, InvalidOrder, OrderNotFound, InsufficientFunds, ArgumentsRequired, BadSymbol, BadRequest, RequestTimeout } = require ('./base/errors');
+const { AuthenticationError, ExchangeError, PermissionDenied, ExchangeNotAvailable, OnMaintenance, InvalidOrder, OrderNotFound, InsufficientFunds, ArgumentsRequired, BadSymbol, BadRequest, RequestTimeout, NetworkError } = require ('./base/errors');
+const { TRUNCATE } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -21,20 +22,27 @@ module.exports = class huobipro extends Exchange {
'hostname': 'api.huobi.pro', // api.testnet.huobi.pro
'pro': true,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchTickers': true,
- 'fetchDepositAddress': true,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchTradingLimits': true,
- 'fetchMyTrades': true,
- 'withdraw': true,
'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTradingLimits': true,
'fetchWithdrawals': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1min',
@@ -62,10 +70,10 @@ module.exports = class huobipro extends Exchange {
'v2Public': 'https://{hostname}',
'v2Private': 'https://{hostname}',
},
- 'www': 'https://www.huobi.pro',
- 'referral': 'https://www.huobi.co/en-us/topic/invited/?invite_code=rwrd3',
+ 'www': 'https://www.huobi.com',
+ 'referral': 'https://www.huobi.com/en-us/topic/invited/?invite_code=rwrd3',
'doc': 'https://huobiapi.github.io/docs/spot/v1/cn/',
- 'fees': 'https://www.huobi.pro/about/fee/',
+ 'fees': 'https://www.huobi.com/about/fee/',
},
'api': {
'v2Public': {
@@ -75,12 +83,29 @@ module.exports = class huobipro extends Exchange {
},
'v2Private': {
'get': [
+ 'account/ledger',
'account/withdraw/quota',
+ 'account/withdraw/address', // 提币地址查询(限母用户可用)
'account/deposit/address',
'reference/transact-fee-rate',
+ 'account/asset-valuation', // 获取账户资产估值
+ 'point/account', // 点卡余额查询
+ 'sub-user/user-list', // 获取子用户列表
+ 'sub-user/user-state', // 获取特定子用户的用户状态
+ 'sub-user/account-list', // 获取特定子用户的账户列表
+ 'sub-user/deposit-address', // 子用户充币地址查询
+ 'sub-user/query-deposit', // 子用户充币记录查询
+ 'user/api-key', // 母子用户API key信息查询
],
'post': [
- 'sub-user/management',
+ 'point/transfer', // 点卡划转
+ 'sub-user/management', // 冻结/解冻子用户
+ 'sub-user/creation', // 子用户创建
+ 'sub-user/tradable-market', // 设置子用户交易权限
+ 'sub-user/transferability', // 设置子用户资产转出权限
+ 'sub-user/api-key-generation', // 子用户API key创建
+ 'sub-user/api-key-modification', // 修改子用户API key
+ 'sub-user/api-key-deletion', // 删除子用户API key
],
},
'market': {
@@ -110,6 +135,7 @@ module.exports = class huobipro extends Exchange {
'account/accounts/{sub-uid}',
'account/history',
'cross-margin/loan-info',
+ 'margin/loan-info', // 查询借币币息率及额度
'fee/fee-rate/get',
'order/openOrders',
'order/orders',
@@ -118,10 +144,13 @@ module.exports = class huobipro extends Exchange {
'order/orders/getClientOrder',
'order/history', // 查询当前委托、历史委托
'order/matchresults', // 查询当前成交、历史成交
- 'dw/withdraw-virtual/addresses', // 查询虚拟币提现地址
+ 'dw/withdraw-virtual/addresses', // 查询虚拟币提现地址(Deprecated)
'query/deposit-withdraw',
+ 'margin/loan-info',
'margin/loan-orders', // 借贷订单
'margin/accounts/balance', // 借贷账户详情
+ 'cross-margin/loan-orders', // 查询借币订单
+ 'cross-margin/accounts/balance', // 借币账户详情
'points/actions',
'points/orders',
'subuser/aggregate-balance',
@@ -129,6 +158,7 @@ module.exports = class huobipro extends Exchange {
'stable-coin/quote',
],
'post': [
+ 'account/transfer', // 资产划转(该节点为母用户和子用户进行资产划转的通用接口。)
'futures/transfer',
'order/batch-orders',
'order/orders/place', // 创建并执行一个新订单 (一步下单, 推荐使用)
@@ -141,12 +171,16 @@ module.exports = class huobipro extends Exchange {
'dw/balance/transfer', // 资产划转
'dw/withdraw/api/create', // 申请提现虚拟币
'dw/withdraw-virtual/create', // 申请提现虚拟币
- 'dw/withdraw-virtual/{id}/place', // 确认申请虚拟币提现
+ 'dw/withdraw-virtual/{id}/place', // 确认申请虚拟币提现(Deprecated)
'dw/withdraw-virtual/{id}/cancel', // 申请取消提现虚拟币
'dw/transfer-in/margin', // 现货账户划入至借贷账户
'dw/transfer-out/margin', // 借贷账户划出至现货账户
'margin/orders', // 申请借贷
'margin/orders/{id}/repay', // 归还借贷
+ 'cross-margin/transfer-in', // 资产划转
+ 'cross-margin/transfer-out', // 资产划转
+ 'cross-margin/orders', // 申请借币
+ 'cross-margin/orders/{id}/repay', // 归还借币
'stable-coin/exchange',
'subuser/transfer',
],
@@ -180,10 +214,12 @@ module.exports = class huobipro extends Exchange {
'api-signature-check-failed': AuthenticationError,
'api-signature-not-valid': AuthenticationError, // {"status":"error","err-code":"api-signature-not-valid","err-msg":"Signature not valid: Incorrect Access key [Access key错误]","data":null}
'base-record-invalid': OrderNotFound, // https://github.com/ccxt/ccxt/issues/5750
+ 'base-symbol-trade-disabled': BadSymbol, // {"status":"error","err-code":"base-symbol-trade-disabled","err-msg":"Trading is disabled for this symbol","data":null}
+ 'base-symbol-error': BadSymbol, // {"status":"error","err-code":"base-symbol-error","err-msg":"The symbol is invalid","data":null}
+ 'system-maintenance': OnMaintenance, // {"status": "error", "err-code": "system-maintenance", "err-msg": "System is in maintenance!", "data": null}
// err-msg
'invalid symbol': BadSymbol, // {"ts":1568813334794,"status":"error","err-code":"invalid-parameter","err-msg":"invalid symbol"}
- 'invalid-parameter': BadRequest, // {"ts":1576210479343,"status":"error","err-code":"invalid-parameter","err-msg":"symbol trade not open now"}
- 'base-symbol-trade-disabled': BadSymbol, // {"status":"error","err-code":"base-symbol-trade-disabled","err-msg":"Trading is disabled for this symbol","data":null}
+ 'symbol trade not open now': BadSymbol, // {"ts":1576210479343,"status":"error","err-code":"invalid-parameter","err-msg":"symbol trade not open now"}
},
},
'options': {
@@ -202,6 +238,11 @@ module.exports = class huobipro extends Exchange {
// https://github.com/ccxt/ccxt/issues/2873
'GET': 'Themis', // conflict with GET (Guaranteed Entrance Token, GET Protocol)
'HOT': 'Hydro Protocol', // conflict with HOT (Holo) https://github.com/ccxt/ccxt/issues/4929
+ // https://github.com/ccxt/ccxt/issues/7399
+ // https://coinmarketcap.com/currencies/pnetwork/
+ // https://coinmarketcap.com/currencies/penta/markets/
+ // https://en.cryptonomist.ch/blog/eidoo/the-edo-to-pnt-upgrade-what-you-need-to-know-updated/
+ 'PNT': 'Penta',
},
});
}
@@ -273,13 +314,17 @@ module.exports = class huobipro extends Exchange {
};
}
+ costToPrecision (symbol, cost) {
+ return this.decimalToPrecision (cost, TRUNCATE, this.markets[symbol]['precision']['cost'], this.precisionMode);
+ }
+
async fetchMarkets (params = {}) {
const method = this.options['fetchMarketsMethod'];
const response = await this[method] (params);
const markets = this.safeValue (response, 'data');
const numMarkets = markets.length;
if (numMarkets < 1) {
- throw new ExchangeError (this.id + ' publicGetCommonSymbols returned empty response: ' + this.json (markets));
+ throw new NetworkError (this.id + ' publicGetCommonSymbols returned empty response: ' + this.json (markets));
}
const result = [];
for (let i = 0; i < markets.length; i++) {
@@ -291,8 +336,9 @@ module.exports = class huobipro extends Exchange {
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
const precision = {
- 'amount': market['amount-precision'],
- 'price': market['price-precision'],
+ 'amount': this.safeInteger (market, 'amount-precision'),
+ 'price': this.safeInteger (market, 'price-precision'),
+ 'cost': this.safeInteger (market, 'value-precision'),
};
const maker = (base === 'OMG') ? 0 : 0.2 / 100;
const taker = (base === 'OMG') ? 0 : 0.2 / 100;
@@ -407,10 +453,7 @@ module.exports = class huobipro extends Exchange {
}
const baseVolume = this.safeFloat (ticker, 'amount');
const quoteVolume = this.safeFloat (ticker, 'vol');
- let vwap = undefined;
- if (baseVolume !== undefined && quoteVolume !== undefined && baseVolume > 0) {
- vwap = quoteVolume / baseVolume;
- }
+ const vwap = this.vwap (baseVolume, quoteVolume);
return {
'symbol': symbol,
'timestamp': timestamp,
@@ -466,7 +509,7 @@ module.exports = class huobipro extends Exchange {
//
if ('tick' in response) {
if (!response['tick']) {
- throw new ExchangeError (this.id + ' fetchOrderBook() returned empty response: ' + this.json (response));
+ throw new BadSymbol (this.id + ' fetchOrderBook() returned empty response: ' + this.json (response));
}
const tick = this.safeValue (response, 'tick');
const timestamp = this.safeInteger (tick, 'ts', this.safeInteger (response, 'ts'));
@@ -519,15 +562,12 @@ module.exports = class huobipro extends Exchange {
const result = {};
for (let i = 0; i < tickers.length; i++) {
const marketId = this.safeString (tickers[i], 'symbol');
- const market = this.safeValue (this.markets_by_id, marketId);
- let symbol = marketId;
- if (market !== undefined) {
- symbol = market['symbol'];
- const ticker = this.parseTicker (tickers[i], market);
- ticker['timestamp'] = timestamp;
- ticker['datetime'] = this.iso8601 (timestamp);
- result[symbol] = ticker;
- }
+ const market = this.safeMarket (marketId);
+ const symbol = market['symbol'];
+ const ticker = this.parseTicker (tickers[i], market);
+ ticker['timestamp'] = timestamp;
+ ticker['datetime'] = this.iso8601 (timestamp);
+ result[symbol] = ticker;
}
return this.filterByArray (result, 'symbol', symbols);
}
@@ -547,16 +587,26 @@ module.exports = class huobipro extends Exchange {
//
// fetchMyTrades (private)
//
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (trade, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ // {
+ // 'symbol': 'swftcbtc',
+ // 'fee-currency': 'swftc',
+ // 'filled-fees': '0',
+ // 'source': 'spot-api',
+ // 'id': 83789509854000,
+ // 'type': 'buy-limit',
+ // 'order-id': 83711103204909,
+ // 'filled-points': '0.005826843283532154',
+ // 'fee-deduct-currency': 'ht',
+ // 'filled-amount': '45941.53',
+ // 'price': '0.0000001401',
+ // 'created-at': 1597933260729,
+ // 'match-id': 100087455560,
+ // 'role': 'maker',
+ // 'trade-id': 100050305348
+ // },
+ //
+ const marketId = this.safeString (trade, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.safeInteger2 (trade, 'ts', 'created-at');
const order = this.safeString (trade, 'order-id');
let side = this.safeString (trade, 'direction');
@@ -579,7 +629,7 @@ module.exports = class huobipro extends Exchange {
let feeCost = this.safeFloat (trade, 'filled-fees');
let feeCurrency = undefined;
if (market !== undefined) {
- feeCurrency = (side === 'buy') ? market['base'] : market['quote'];
+ feeCurrency = this.safeCurrencyCode (this.safeString (trade, 'fee-currency'));
}
const filledPoints = this.safeFloat (trade, 'filled-points');
if (filledPoints !== undefined) {
@@ -679,7 +729,19 @@ module.exports = class huobipro extends Exchange {
return this.filterBySymbolSinceLimit (result, symbol, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "amount":1.2082,
+ // "open":0.025096,
+ // "close":0.025095,
+ // "high":0.025096,
+ // "id":1591515300,
+ // "count":6,
+ // "low":0.025095,
+ // "vol":0.0303205097
+ // }
+ //
return [
this.safeTimestamp (ohlcv, 'id'),
this.safeFloat (ohlcv, 'open'),
@@ -701,7 +763,20 @@ module.exports = class huobipro extends Exchange {
request['size'] = limit;
}
const response = await this.marketGetHistoryKline (this.extend (request, params));
- return this.parseOHLCVs (response['data'], market, timeframe, since, limit);
+ //
+ // {
+ // "status":"ok",
+ // "ch":"market.ethbtc.kline.1min",
+ // "ts":1591515374371,
+ // "data":[
+ // {"amount":0.0,"open":0.025095,"close":0.025095,"high":0.025095,"id":1591515360,"count":0,"low":0.025095,"vol":0.0},
+ // {"amount":1.2082,"open":0.025096,"close":0.025095,"high":0.025096,"id":1591515300,"count":6,"low":0.025095,"vol":0.0303205097},
+ // {"amount":0.0648,"open":0.025096,"close":0.025096,"high":0.025096,"id":1591515240,"count":2,"low":0.025096,"vol":0.0016262208},
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async fetchAccounts (params = {}) {
@@ -984,18 +1059,8 @@ module.exports = class huobipro extends Exchange {
type = orderType[1];
status = this.parseOrderStatus (this.safeString (order, 'state'));
}
- let symbol = undefined;
- if (market === undefined) {
- if ('symbol' in order) {
- if (order['symbol'] in this.markets_by_id) {
- const marketId = order['symbol'];
- market = this.markets_by_id[marketId];
- }
- }
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market);
const timestamp = this.safeInteger (order, 'created-at');
let amount = this.safeFloat (order, 'amount');
const filled = this.safeFloat2 (order, 'filled-amount', 'field-amount'); // typo in their API, filled amount
@@ -1039,8 +1104,10 @@ module.exports = class huobipro extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'average': average,
'cost': cost,
'amount': amount,
@@ -1068,9 +1135,10 @@ module.exports = class huobipro extends Exchange {
} else {
// despite that cost = amount * price is in quote currency and should have quote precision
// the exchange API requires the cost supplied in 'amount' to be of base precision
- // more about it here: https://github.com/ccxt/ccxt/pull/4395
- // we use priceToPrecision instead of amountToPrecision here
- // because in this case the amount is in the quote currency
+ // more about it here:
+ // https://github.com/ccxt/ccxt/pull/4395
+ // https://github.com/ccxt/ccxt/issues/7611
+ // we use amountToPrecision here because the exchange requires cost in base precision
request['amount'] = this.costToPrecision (symbol, parseFloat (amount) * parseFloat (price));
}
} else {
diff --git a/TaskServer/node_modules/ccxt/js/huobiru.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/huobiru.js
similarity index 93%
rename from TaskServer/node_modules/ccxt/js/huobiru.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/huobiru.js
index b628d3dc4..21e0de149 100644
--- a/TaskServer/node_modules/ccxt/js/huobiru.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/huobiru.js
@@ -20,7 +20,6 @@ module.exports = class huobiru extends huobipro {
'market': 'https://{hostname}/api',
'public': 'https://{hostname}/api',
'private': 'https://{hostname}/api',
- 'zendesk': 'https://huobiglobal.zendesk.com/hc/en-us/articles',
},
'www': 'https://www.huobi.com.ru/ru-ru',
'referral': 'https://www.huobi.com.ru/invite?invite_code=esc74',
diff --git a/TaskServer/node_modules/ccxt/js/ice3x.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/ice3x.js
similarity index 93%
rename from TaskServer/node_modules/ccxt/js/ice3x.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/ice3x.js
index 73230a5b1..42e54b79f 100644
--- a/TaskServer/node_modules/ccxt/js/ice3x.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/ice3x.js
@@ -16,20 +16,24 @@ module.exports = class ice3x extends Exchange {
'rateLimit': 1000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchCurrencies': true,
- 'fetchTickers': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
- 'fetchMyTrades': true,
'fetchDepositAddress': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/38012176-11616c32-3269-11e8-9f05-e65cf885bb15.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87460809-1dd06c00-c616-11ea-98ad-7d5e1cb7fcdd.jpg',
'api': 'https://ice3x.com/api',
- 'www': [
- 'https://ice3x.com',
- 'https://ice3x.co.za',
- ],
+ 'www': 'https://ice3x.com', // 'https://ice3x.co.za',
'doc': 'https://ice3x.co.za/ice-cubed-bitcoin-exchange-api-documentation-1-june-2017',
'fees': [
'https://help.ice3.com/support/solutions/articles/11000033293-trading-fees',
@@ -209,7 +213,7 @@ module.exports = class ice3x extends Exchange {
result[symbol] = this.parseTicker (ticker, market);
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -340,8 +344,10 @@ module.exports = class ice3x extends Exchange {
'status': status,
'symbol': symbol,
'type': 'limit',
- 'side': this.safeStrin (order, 'type'),
+ 'timeInForce': undefined,
+ 'side': this.safeString (order, 'type'),
'price': price,
+ 'stopPrice': undefined,
'cost': undefined,
'amount': amount,
'filled': filled,
@@ -373,8 +379,6 @@ module.exports = class ice3x extends Exchange {
'remaining': amount,
'info': response,
}, market);
- const id = order['id'];
- this.orders[id] = order;
return order;
}
@@ -391,15 +395,21 @@ module.exports = class ice3x extends Exchange {
'order _id': id,
};
const response = await this.privatePostOrderInfo (this.extend (request, params));
- const order = this.safeValue (response['response'], 'entity');
+ const data = this.safeValue (response, 'response', {});
+ const order = this.safeValue (data, 'entity');
return this.parseOrder (order);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privatePostOrderList (params);
- const orders = this.safeValue (response['response'], 'entities');
- return this.parseOrders (orders, undefined, since, limit);
+ const data = this.safeValue (response, 'response', {});
+ const orders = this.safeValue (data, 'entities', []);
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ return this.parseOrders (orders, market, since, limit);
}
async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -415,7 +425,8 @@ module.exports = class ice3x extends Exchange {
request['date_from'] = parseInt (since / 1000);
}
const response = await this.privatePostTradeList (this.extend (request, params));
- const trades = this.safeValue (response['response'], 'entities');
+ const data = this.safeValue (response, 'response', {});
+ const trades = this.safeValue (data, 'entities', []);
return this.parseTrades (trades, market, since, limit);
}
@@ -426,7 +437,8 @@ module.exports = class ice3x extends Exchange {
'currency_id': currency['id'],
};
const response = await this.privatePostBalanceInfo (this.extend (request, params));
- const balance = this.safeValue (response['response'], 'entity');
+ const data = this.safeValue (response, 'response', {});
+ const balance = this.safeValue (data, 'entity', {});
const address = this.safeString (balance, 'address');
const status = address ? 'ok' : 'none';
return {
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/idex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/idex.js
new file mode 100644
index 000000000..d70fa94f4
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/idex.js
@@ -0,0 +1,1305 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { PAD_WITH_ZERO } = require ('./base/functions/number');
+const { InvalidOrder, InsufficientFunds, ExchangeError, ExchangeNotAvailable, DDoSProtection, BadRequest, NotSupported, InvalidAddress, AuthenticationError } = require ('./base/errors');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class idex extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'idex',
+ 'name': 'IDEX',
+ 'countries': [ 'US' ],
+ 'rateLimit': 1500,
+ 'version': 'v2',
+ 'certified': true,
+ 'pro': true,
+ 'requiresWeb3': true,
+ 'has': {
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchCurrencies': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchClosedOrders': true,
+ 'fetchOrders': false,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': false,
+ 'fetchDeposits': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
+ },
+ 'timeframes': {
+ '1m': '1m',
+ '5m': '5m',
+ '15m': '15m',
+ '30m': '30m',
+ '1h': '1h',
+ '6h': '6h',
+ '1d': '1d',
+ },
+ 'urls': {
+ 'test': {
+ 'public': 'https://api-sandbox.idex.io',
+ 'private': 'https://api-sandbox.idex.io',
+ },
+ 'logo': 'https://user-images.githubusercontent.com/51840849/94481303-2f222100-01e0-11eb-97dd-bc14c5943a86.jpg',
+ 'api': {
+ 'public': 'https://api.idex.io',
+ 'private': 'https://api.idex.io',
+ },
+ 'www': 'https://idex.io',
+ 'doc': [
+ 'https://docs.idex.io/',
+ ],
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'ping',
+ 'time',
+ 'exchange',
+ 'assets',
+ 'markets',
+ 'tickers',
+ 'candles',
+ 'trades',
+ 'orderbook',
+ 'wsToken',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'user',
+ 'wallets',
+ 'balances',
+ 'orders',
+ 'fills',
+ 'deposits',
+ 'withdrawals',
+ ],
+ 'post': [
+ 'wallets',
+ 'orders',
+ 'orders/test',
+ 'withdrawals',
+ ],
+ 'delete': [
+ 'orders',
+ ],
+ },
+ },
+ 'options': {
+ 'defaultTimeInForce': 'gtc',
+ 'defaultSelfTradePrevention': 'cn',
+ },
+ 'exceptions': {
+ 'INVALID_ORDER_QUANTITY': InvalidOrder,
+ 'INSUFFICIENT_FUNDS': InsufficientFunds,
+ 'SERVICE_UNAVAILABLE': ExchangeNotAvailable,
+ 'EXCEEDED_RATE_LIMIT': DDoSProtection,
+ 'INVALID_PARAMETER': BadRequest,
+ 'WALLET_NOT_ASSOCIATED': InvalidAddress,
+ 'INVALID_WALLET_SIGNATURE': AuthenticationError,
+ },
+ 'requiredCredentials': {
+ 'walletAddress': true,
+ 'privateKey': true,
+ 'apiKey': true,
+ 'secret': true,
+ },
+ 'paddingMode': PAD_WITH_ZERO,
+ 'commonCurrencies': {},
+ 'requireCredentials': {
+ 'privateKey': true,
+ 'apiKey': true,
+ 'secret': true,
+ },
+ });
+ }
+
+ async fetchMarkets (params = {}) {
+ // [
+ // {
+ // market: 'DIL-ETH',
+ // status: 'active',
+ // baseAsset: 'DIL',
+ // baseAssetPrecision: 8,
+ // quoteAsset: 'ETH',
+ // quoteAssetPrecision: 8
+ // }, ...
+ // ]
+ const response = await this.publicGetMarkets (params);
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const entry = response[i];
+ const marketId = this.safeString (entry, 'market');
+ const baseId = this.safeString (entry, 'baseAsset');
+ const quoteId = this.safeString (entry, 'quoteAsset');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const basePrecision = this.safeInteger (entry, 'baseAssetPrecision');
+ const quotePrecision = this.safeInteger (entry, 'quoteAssetPrecision');
+ const status = this.safeString (entry, 'status');
+ const active = status === 'active';
+ const precision = {
+ 'amount': basePrecision,
+ 'price': quotePrecision,
+ };
+ result.push ({
+ 'symbol': symbol,
+ 'id': marketId,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'active': active,
+ 'info': entry,
+ 'precision': precision,
+ 'limits': {
+ 'amount': {
+ 'min': Math.pow (10, -precision['amount']),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ },
+ });
+ }
+ return result;
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ };
+ // [
+ // {
+ // market: 'DIL-ETH',
+ // time: 1598367493008,
+ // open: '0.09695361',
+ // high: '0.10245881',
+ // low: '0.09572507',
+ // close: '0.09917079',
+ // closeQuantity: '0.71320950',
+ // baseVolume: '309.17380612',
+ // quoteVolume: '30.57633981',
+ // percentChange: '2.28',
+ // numTrades: 205,
+ // ask: '0.09910476',
+ // bid: '0.09688340',
+ // sequence: 3902
+ // }
+ // ]
+ const response = await this.publicGetTickers (this.extend (request, params));
+ const ticker = this.safeValue (response, 0);
+ return this.parseTicker (ticker, market);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ // [
+ // {
+ // market: 'DIL-ETH',
+ // time: 1598367493008,
+ // open: '0.09695361',
+ // high: '0.10245881',
+ // low: '0.09572507',
+ // close: '0.09917079',
+ // closeQuantity: '0.71320950',
+ // baseVolume: '309.17380612',
+ // quoteVolume: '30.57633981',
+ // percentChange: '2.28',
+ // numTrades: 205,
+ // ask: '0.09910476',
+ // bid: '0.09688340',
+ // sequence: 3902
+ // }, ...
+ // ]
+ const response = await this.publicGetTickers (params);
+ return this.parseTickers (response, symbols);
+ }
+
+ parseTickers (rawTickers, symbols = undefined) {
+ const tickers = [];
+ for (let i = 0; i < rawTickers.length; i++) {
+ tickers.push (this.parseTicker (rawTickers[i]));
+ }
+ return this.filterByArray (tickers, 'symbol', symbols);
+ }
+
+ parseTicker (ticker, market = undefined) {
+ // {
+ // market: 'DIL-ETH',
+ // time: 1598367493008,
+ // open: '0.09695361',
+ // high: '0.10245881',
+ // low: '0.09572507',
+ // close: '0.09917079',
+ // closeQuantity: '0.71320950',
+ // baseVolume: '309.17380612',
+ // quoteVolume: '30.57633981',
+ // percentChange: '2.28',
+ // numTrades: 205,
+ // ask: '0.09910476',
+ // bid: '0.09688340',
+ // sequence: 3902
+ // }
+ const marketId = this.safeString (ticker, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const baseVolume = this.safeFloat (ticker, 'baseVolume');
+ const quoteVolume = this.safeFloat (ticker, 'quoteVolume');
+ const timestamp = this.safeInteger (ticker, 'time');
+ const open = this.safeFloat (ticker, 'open');
+ const high = this.safeFloat (ticker, 'high');
+ const low = this.safeFloat (ticker, 'low');
+ const close = this.safeFloat (ticker, 'close');
+ const ask = this.safeFloat (ticker, 'ask');
+ const bid = this.safeFloat (ticker, 'bid');
+ let percentage = this.safeFloat (ticker, 'percentChange');
+ if (percentage !== undefined) {
+ percentage = 1 + percentage / 100;
+ }
+ let change = undefined;
+ if ((close !== undefined) && (open !== undefined)) {
+ change = close - open;
+ }
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': high,
+ 'low': low,
+ 'bid': bid,
+ 'bidVolume': undefined,
+ 'ask': ask,
+ 'askVolume': undefined,
+ 'vwap': undefined,
+ 'open': open,
+ 'close': close,
+ 'last': close,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': undefined,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ 'interval': timeframe,
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.publicGetCandles (this.extend (request, params));
+ if (Array.isArray (response)) {
+ // [
+ // {
+ // start: 1598345580000,
+ // open: '0.09771286',
+ // high: '0.09771286',
+ // low: '0.09771286',
+ // close: '0.09771286',
+ // volume: '1.45340410',
+ // sequence: 3853
+ // }, ...
+ // ]
+ return this.parseOHLCVs (response, market, timeframe, since, limit);
+ } else {
+ // {"nextTime":1595536440000}
+ return [];
+ }
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ // {
+ // start: 1598345580000,
+ // open: '0.09771286',
+ // high: '0.09771286',
+ // low: '0.09771286',
+ // close: '0.09771286',
+ // volume: '1.45340410',
+ // sequence: 3853
+ // }
+ const timestamp = this.safeInteger (ohlcv, 'start');
+ const open = this.safeFloat (ohlcv, 'open');
+ const high = this.safeFloat (ohlcv, 'high');
+ const low = this.safeFloat (ohlcv, 'low');
+ const close = this.safeFloat (ohlcv, 'close');
+ const volume = this.safeFloat (ohlcv, 'volume');
+ return [ timestamp, open, high, low, close, volume ];
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ };
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ // [
+ // {
+ // fillId: 'b5467d00-b13e-3fa9-8216-dd66735550fc',
+ // price: '0.09771286',
+ // quantity: '1.45340410',
+ // quoteQuantity: '0.14201627',
+ // time: 1598345638994,
+ // makerSide: 'buy',
+ // sequence: 3853
+ // }, ...
+ // ]
+ const response = await this.publicGetTrades (this.extend (request, params));
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ parseTrade (trade, market = undefined) {
+ // public trades
+ // {
+ // fillId: 'b5467d00-b13e-3fa9-8216-dd66735550fc',
+ // price: '0.09771286',
+ // quantity: '1.45340410',
+ // quoteQuantity: '0.14201627',
+ // time: 1598345638994,
+ // makerSide: 'buy',
+ // sequence: 3853
+ // }
+ // private trades
+ // {
+ // fillId: '48582d10-b9bb-3c4b-94d3-e67537cf2472',
+ // price: '0.09905990',
+ // quantity: '0.40000000',
+ // quoteQuantity: '0.03962396',
+ // time: 1598873478762,
+ // makerSide: 'sell',
+ // sequence: 5053,
+ // market: 'DIL-ETH',
+ // orderId: '7cdc8e90-eb7d-11ea-9e60-4118569f6e63',
+ // side: 'buy',
+ // fee: '0.00080000',
+ // feeAsset: 'DIL',
+ // gas: '0.00857497',
+ // liquidity: 'taker',
+ // txId: '0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65',
+ // txStatus: 'mined'
+ // }
+ const id = this.safeString (trade, 'fillId');
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'quantity');
+ const cost = this.safeFloat (trade, 'quoteQuantity');
+ const timestamp = this.safeInteger (trade, 'time');
+ const marketId = this.safeString (trade, 'market');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ // this code handles the duality of public vs private trades
+ const makerSide = this.safeString (trade, 'makerSide');
+ const oppositeSide = (makerSide === 'buy') ? 'sell' : 'buy';
+ const side = this.safeString (trade, 'side', oppositeSide);
+ const takerOrMaker = this.safeString (trade, 'liquidity', 'taker');
+ const feeCost = this.safeFloat (trade, 'fee');
+ let fee = undefined;
+ if (feeCost !== undefined) {
+ const feeCurrencyId = this.safeString (trade, 'feeAsset');
+ fee = {
+ 'cost': feeCost,
+ 'currency': this.safeCurrencyCode (feeCurrencyId),
+ };
+ }
+ const orderId = this.safeString (trade, 'orderId');
+ return {
+ 'info': trade,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'id': id,
+ 'order': orderId,
+ 'type': 'limit',
+ 'side': side,
+ 'takerOrMaker': takerOrMaker,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'fee': fee,
+ };
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'market': market['id'],
+ 'level': 2,
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ // {
+ // sequence: 36416753,
+ // bids: [
+ // [ '0.09672815', '8.22284267', 1 ],
+ // [ '0.09672814', '1.83685554', 1 ],
+ // [ '0.09672143', '4.10962617', 1 ],
+ // [ '0.09658884', '4.03863759', 1 ],
+ // [ '0.09653781', '3.35730684', 1 ],
+ // [ '0.09624660', '2.54163586', 1 ],
+ // [ '0.09617490', '1.93065030', 1 ]
+ // ],
+ // asks: [
+ // [ '0.09910476', '3.22840154', 1 ],
+ // [ '0.09940587', '3.39796593', 1 ],
+ // [ '0.09948189', '4.25088898', 1 ],
+ // [ '0.09958362', '2.42195784', 1 ],
+ // [ '0.09974393', '4.25234367', 1 ],
+ // [ '0.09995250', '3.40192141', 1 ]
+ // ]
+ // }
+ const response = await this.publicGetOrderbook (this.extend (request, params));
+ const nonce = this.safeInteger (response, 'sequence');
+ return {
+ 'timestamp': undefined,
+ 'datetime': undefined,
+ 'nonce': nonce,
+ 'bids': this.parseSide (response, 'bids'),
+ 'asks': this.parseSide (response, 'asks'),
+ };
+ }
+
+ parseSide (book, side) {
+ const bookSide = this.safeValue (book, side, []);
+ const result = [];
+ for (let i = 0; i < bookSide.length; i++) {
+ const order = bookSide[i];
+ const price = this.safeFloat (order, 0);
+ const amount = this.safeFloat (order, 1);
+ const orderCount = this.safeInteger (order, 2);
+ result.push ([ price, amount, orderCount ]);
+ }
+ const descending = side === 'bids';
+ return this.sortBy (result, 0, descending);
+ }
+
+ async fetchCurrencies (params = {}) {
+ // [
+ // {
+ // name: 'Ether',
+ // symbol: 'ETH',
+ // contractAddress: '0x0000000000000000000000000000000000000000',
+ // assetDecimals: 18,
+ // exchangeDecimals: 8
+ // }, ..
+ // ]
+ const response = await this.publicGetAssets (params);
+ const result = {};
+ for (let i = 0; i < response.length; i++) {
+ const entry = response[i];
+ const name = this.safeString (entry, 'name');
+ const currencyId = this.safeString (entry, 'symbol');
+ const precision = this.safeInteger (entry, 'exchangeDecimals');
+ const code = this.safeCurrencyCode (currencyId);
+ const lot = Math.pow (-10, precision);
+ result[code] = {
+ 'id': currencyId,
+ 'code': code,
+ 'info': entry,
+ 'type': undefined,
+ 'name': name,
+ 'active': undefined,
+ 'fee': undefined,
+ 'precision': precision,
+ 'limits': {
+ 'amount': { 'min': lot, 'max': undefined },
+ 'price': { 'min': lot, 'max': undefined },
+ 'cost': { 'min': undefined, 'max': undefined },
+ 'withdraw': { 'min': lot, 'max': undefined },
+ },
+ };
+ }
+ return result;
+ }
+
+ async fetchBalance (params = {}) {
+ this.checkRequiredCredentials ();
+ await this.loadMarkets ();
+ const nonce1 = this.uuidv1 ();
+ const request = {
+ 'nonce': nonce1,
+ 'wallet': this.walletAddress,
+ };
+ // [
+ // {
+ // asset: 'DIL',
+ // quantity: '0.00000000',
+ // availableForTrade: '0.00000000',
+ // locked: '0.00000000',
+ // usdValue: null
+ // }, ...
+ // ]
+ const extendedRequest = this.extend (request, params);
+ if (extendedRequest['wallet'] === undefined) {
+ throw new BadRequest (this.id + ' wallet is undefined, set this.walletAddress or "address" in params');
+ }
+ let response = undefined;
+ try {
+ response = await this.privateGetBalances (extendedRequest);
+ } catch (e) {
+ if (e instanceof InvalidAddress) {
+ const walletAddress = extendedRequest['wallet'];
+ await this.associateWallet (walletAddress);
+ response = await this.privateGetBalances (extendedRequest);
+ } else {
+ throw e;
+ }
+ }
+ const result = {
+ 'info': response,
+ };
+ for (let i = 0; i < response.length; i++) {
+ const entry = response[i];
+ const currencyId = this.safeString (entry, 'asset');
+ const code = this.safeCurrencyCode (currencyId);
+ const total = this.safeFloat (entry, 'quantity');
+ const free = this.safeFloat (entry, 'availableForTrade');
+ const used = this.safeFloat (entry, 'locked');
+ result[code] = {
+ 'free': free,
+ 'used': used,
+ 'total': total,
+ };
+ }
+ return this.parseBalance (result);
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ this.checkRequiredCredentials ();
+ await this.loadMarkets ();
+ let market = undefined;
+ const request = {
+ 'nonce': this.uuidv1 (),
+ 'wallet': this.walletAddress,
+ };
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ // [
+ // {
+ // fillId: '48582d10-b9bb-3c4b-94d3-e67537cf2472',
+ // price: '0.09905990',
+ // quantity: '0.40000000',
+ // quoteQuantity: '0.03962396',
+ // time: 1598873478762,
+ // makerSide: 'sell',
+ // sequence: 5053,
+ // market: 'DIL-ETH',
+ // orderId: '7cdc8e90-eb7d-11ea-9e60-4118569f6e63',
+ // side: 'buy',
+ // fee: '0.00080000',
+ // feeAsset: 'DIL',
+ // gas: '0.00857497',
+ // liquidity: 'taker',
+ // txId: '0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65',
+ // txStatus: 'mined'
+ // }
+ // ]
+ const extendedRequest = this.extend (request, params);
+ if (extendedRequest['wallet'] === undefined) {
+ throw new BadRequest (this.id + ' walletAddress is undefined, set this.walletAddress or "address" in params');
+ }
+ let response = undefined;
+ try {
+ response = await this.privateGetFills (extendedRequest);
+ } catch (e) {
+ if (e instanceof InvalidAddress) {
+ const walletAddress = extendedRequest['wallet'];
+ await this.associateWallet (walletAddress);
+ response = await this.privateGetFills (extendedRequest);
+ } else {
+ throw e;
+ }
+ }
+ return this.parseTrades (response, market, since, limit);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ const request = {
+ 'orderId': id,
+ };
+ return await this.fetchOrdersHelper (symbol, undefined, undefined, this.extend (request, params));
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'closed': false,
+ };
+ return await this.fetchOrdersHelper (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'closed': true,
+ };
+ return await this.fetchOrdersHelper (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchOrdersHelper (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'nonce': this.uuidv1 (),
+ 'wallet': this.walletAddress,
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['market'] = market['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ const response = await this.privateGetOrders (this.extend (request, params));
+ // fetchClosedOrders / fetchOpenOrders
+ // [
+ // {
+ // "market": "DIL-ETH",
+ // "orderId": "7cdc8e90-eb7d-11ea-9e60-4118569f6e63",
+ // "wallet": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
+ // "time": 1598873478650,
+ // "status": "filled",
+ // "type": "limit",
+ // "side": "buy",
+ // "originalQuantity": "0.40000000",
+ // "executedQuantity": "0.40000000",
+ // "cumulativeQuoteQuantity": "0.03962396",
+ // "avgExecutionPrice": "0.09905990",
+ // "price": "1.00000000",
+ // "fills": [
+ // {
+ // "fillId": "48582d10-b9bb-3c4b-94d3-e67537cf2472",
+ // "price": "0.09905990",
+ // "quantity": "0.40000000",
+ // "quoteQuantity": "0.03962396",
+ // "time": 1598873478650,
+ // "makerSide": "sell",
+ // "sequence": 5053,
+ // "fee": "0.00080000",
+ // "feeAsset": "DIL",
+ // "gas": "0.00857497",
+ // "liquidity": "taker",
+ // "txId": "0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65",
+ // "txStatus": "mined"
+ // }
+ // ]
+ // }
+ // ]
+ // fetchOrder
+ // { market: 'DIL-ETH',
+ // orderId: '7cdc8e90-eb7d-11ea-9e60-4118569f6e63',
+ // wallet: '0x0AB991497116f7F5532a4c2f4f7B1784488628e1',
+ // time: 1598873478650,
+ // status: 'filled',
+ // type: 'limit',
+ // side: 'buy',
+ // originalQuantity: '0.40000000',
+ // executedQuantity: '0.40000000',
+ // cumulativeQuoteQuantity: '0.03962396',
+ // avgExecutionPrice: '0.09905990',
+ // price: '1.00000000',
+ // fills:
+ // [ { fillId: '48582d10-b9bb-3c4b-94d3-e67537cf2472',
+ // price: '0.09905990',
+ // quantity: '0.40000000',
+ // quoteQuantity: '0.03962396',
+ // time: 1598873478650,
+ // makerSide: 'sell',
+ // sequence: 5053,
+ // fee: '0.00080000',
+ // feeAsset: 'DIL',
+ // gas: '0.00857497',
+ // liquidity: 'taker',
+ // txId: '0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65',
+ // txStatus: 'mined' } ] }
+ if (Array.isArray (response)) {
+ return this.parseOrders (response, market, since, limit);
+ } else {
+ return this.parseOrder (response, market);
+ }
+ }
+
+ parseOrderStatus (status) {
+ // https://docs.idex.io/#order-states-amp-lifecycle
+ const statuses = {
+ 'active': 'open',
+ 'partiallyFilled': 'open',
+ 'rejected': 'canceled',
+ 'filled': 'closed',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // {
+ // "market": "DIL-ETH",
+ // "orderId": "7cdc8e90-eb7d-11ea-9e60-4118569f6e63",
+ // "wallet": "0x0AB991497116f7F5532a4c2f4f7B1784488628e1",
+ // "time": 1598873478650,
+ // "status": "filled",
+ // "type": "limit",
+ // "side": "buy",
+ // "originalQuantity": "0.40000000",
+ // "executedQuantity": "0.40000000",
+ // "cumulativeQuoteQuantity": "0.03962396",
+ // "avgExecutionPrice": "0.09905990",
+ // "price": "1.00000000",
+ // "fills": [
+ // {
+ // "fillId": "48582d10-b9bb-3c4b-94d3-e67537cf2472",
+ // "price": "0.09905990",
+ // "quantity": "0.40000000",
+ // "quoteQuantity": "0.03962396",
+ // "time": 1598873478650,
+ // "makerSide": "sell",
+ // "sequence": 5053,
+ // "fee": "0.00080000",
+ // "feeAsset": "DIL",
+ // "gas": "0.00857497",
+ // "liquidity": "taker",
+ // "txId": "0xeaa02b112c0b8b61bc02fa1776a2b39d6c614e287c1af90df0a2e591da573e65",
+ // "txStatus": "mined"
+ // }
+ // ]
+ // }
+ //
+ const timestamp = this.safeInteger (order, 'time');
+ const fills = this.safeValue (order, 'fills', []);
+ const id = this.safeString (order, 'orderId');
+ const clientOrderId = this.safeString (order, 'clientOrderId');
+ const marketId = this.safeString (order, 'market');
+ const side = this.safeString (order, 'side');
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const trades = this.parseTrades (fills, market);
+ const type = this.safeString (order, 'type');
+ const amount = this.safeFloat (order, 'originalQuantity');
+ const filled = this.safeFloat (order, 'executedQuantity');
+ let remaining = undefined;
+ if ((amount !== undefined) && (filled !== undefined)) {
+ remaining = amount - filled;
+ }
+ const average = this.safeFloat (order, 'avgExecutionPrice');
+ const price = this.safeFloat (order, 'price', average); // for market orders
+ let cost = undefined;
+ if ((amount !== undefined) && (price !== undefined)) {
+ cost = amount * price;
+ }
+ const rawStatus = this.safeString (order, 'status');
+ const status = this.parseOrderStatus (rawStatus);
+ const fee = {
+ 'currency': undefined,
+ 'cost': undefined,
+ };
+ let lastTrade = undefined;
+ for (let i = 0; i < trades.length; i++) {
+ lastTrade = trades[i];
+ fee['currency'] = lastTrade['fee']['currency'];
+ fee['cost'] = this.sum (fee['cost'], lastTrade['fee']['cost']);
+ }
+ const lastTradeTimestamp = this.safeInteger (lastTrade, 'timestamp');
+ return {
+ 'info': order,
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': lastTradeTimestamp,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': trades,
+ };
+ }
+
+ async associateWallet (walletAddress, params = {}) {
+ const nonce = this.uuidv1 ();
+ const noPrefix = this.remove0xPrefix (walletAddress);
+ const byteArray = [
+ this.base16ToBinary (nonce),
+ this.base16ToBinary (noPrefix),
+ ];
+ const binary = this.binaryConcatArray (byteArray);
+ const hash = this.hash (binary, 'keccak', 'hex');
+ const signature = this.signMessageString (hash, this.privateKey);
+ // {
+ // address: '0x0AB991497116f7F5532a4c2f4f7B1784488628e1',
+ // totalPortfolioValueUsd: '0.00',
+ // time: 1598468353626
+ // }
+ const request = {
+ 'parameters': {
+ 'nonce': nonce,
+ 'wallet': walletAddress,
+ },
+ 'signature': signature,
+ };
+ const result = await this.privatePostWallets (request);
+ return result;
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ // https://docs.idex.io/#create-order
+ this.checkRequiredCredentials ();
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const nonce = this.uuidv1 ();
+ let typeEnum = undefined;
+ const stopLossTypeEnums = {
+ 'stopLoss': 3,
+ 'stopLossLimit': 4,
+ 'takeProfit': 5,
+ 'takeProfitLimit': 6,
+ };
+ let stopPriceString = undefined;
+ if ((type === 'stopLossLimit') || (type === 'takeProfitLimit') || ('stopPrice' in params)) {
+ if (!('stopPrice' in params)) {
+ throw new BadRequest (this.id + ' stopPrice is a required parameter for ' + type + 'orders');
+ }
+ stopPriceString = this.priceToPrecision (symbol, params['stopPrice']);
+ }
+ const limitTypeEnums = {
+ 'limit': 1,
+ 'limitMaker': 2,
+ };
+ let priceString = undefined;
+ const typeLower = type.toLowerCase ();
+ const limitOrder = typeLower.indexOf ('limit') > -1;
+ if (type in limitTypeEnums) {
+ typeEnum = limitTypeEnums[type];
+ priceString = this.priceToPrecision (symbol, price);
+ } else if (type in stopLossTypeEnums) {
+ typeEnum = stopLossTypeEnums[type];
+ priceString = this.priceToPrecision (symbol, price);
+ } else if (type === 'market') {
+ typeEnum = 0;
+ } else {
+ throw new BadRequest (this.id + ' ' + type + ' is not a valid order type');
+ }
+ let amountEnum = 0; // base quantity
+ if ('quoteOrderQuantity' in params) {
+ if (type !== 'market') {
+ throw new NotSupported (this.id + ' quoteOrderQuantity is not supported for ' + type + ' orders, only supported for market orders');
+ }
+ amountEnum = 1;
+ amount = this.safeFloat (params, 'quoteOrderQuantity');
+ }
+ const sideEnum = (side === 'buy') ? 0 : 1;
+ const walletBytes = this.remove0xPrefix (this.walletAddress);
+ const orderVersion = 1;
+ const amountString = this.amountToPrecision (symbol, amount);
+ // https://docs.idex.io/#time-in-force
+ const timeInForceEnums = {
+ 'gtc': 0,
+ 'ioc': 2,
+ 'fok': 3,
+ };
+ const defaultTimeInForce = this.safeString (this.options, 'defaultTimeInForce', 'gtc');
+ const timeInForce = this.safeString (params, 'timeInForce', defaultTimeInForce);
+ let timeInForceEnum = undefined;
+ if (timeInForce in timeInForceEnums) {
+ timeInForceEnum = timeInForceEnums[timeInForce];
+ } else {
+ const allOptions = Object.keys (timeInForceEnums);
+ const asString = allOptions.join (', ');
+ throw new BadRequest (this.id + ' ' + timeInForce + ' is not a valid timeInForce, please choose one of ' + asString);
+ }
+ // https://docs.idex.io/#self-trade-prevention
+ const selfTradePreventionEnums = {
+ 'dc': 0,
+ 'co': 1,
+ 'cn': 2,
+ 'cb': 3,
+ };
+ const defaultSelfTradePrevention = this.safeString (this.options, 'defaultSelfTradePrevention', 'cn');
+ const selfTradePrevention = this.safeString (params, 'selfTradePrevention', defaultSelfTradePrevention);
+ let selfTradePreventionEnum = undefined;
+ if (selfTradePrevention in selfTradePreventionEnums) {
+ selfTradePreventionEnum = selfTradePreventionEnums[selfTradePrevention];
+ } else {
+ const allOptions = Object.keys (selfTradePreventionEnums);
+ const asString = allOptions.join (', ');
+ throw new BadRequest (this.id + ' ' + selfTradePrevention + ' is not a valid selfTradePrevention, please choose one of ' + asString);
+ }
+ const byteArray = [
+ this.numberToBE (orderVersion, 1),
+ this.base16ToBinary (nonce),
+ this.base16ToBinary (walletBytes),
+ this.stringToBinary (this.encode (market['id'])), // TODO: refactor to remove either encode or stringToBinary
+ this.numberToBE (typeEnum, 1),
+ this.numberToBE (sideEnum, 1),
+ this.stringToBinary (this.encode (amountString)),
+ this.numberToBE (amountEnum, 1),
+ ];
+ if (limitOrder) {
+ const encodedPrice = this.stringToBinary (this.encode (priceString));
+ byteArray.push (encodedPrice);
+ }
+ if (type in stopLossTypeEnums) {
+ const encodedPrice = this.stringToBinary (this.encode (stopPriceString || priceString));
+ byteArray.push (encodedPrice);
+ }
+ const clientOrderId = this.safeString (params, 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ byteArray.push (this.stringToBinary (this.encode (clientOrderId)));
+ }
+ const after = [
+ this.numberToBE (timeInForceEnum, 1),
+ this.numberToBE (selfTradePreventionEnum, 1),
+ this.numberToBE (0, 8), // unused
+ ];
+ const allBytes = this.arrayConcat (byteArray, after);
+ const binary = this.binaryConcatArray (allBytes);
+ const hash = this.hash (binary, 'keccak', 'hex');
+ const signature = this.signMessageString (hash, this.privateKey);
+ const request = {
+ 'parameters': {
+ 'nonce': nonce,
+ 'market': market['id'],
+ 'side': side,
+ 'type': type,
+ 'wallet': this.walletAddress,
+ 'timeInForce': timeInForce,
+ 'selfTradePrevention': selfTradePrevention,
+ },
+ 'signature': signature,
+ };
+ if (limitOrder) {
+ request['parameters']['price'] = priceString;
+ }
+ if (type in stopLossTypeEnums) {
+ request['parameters']['stopPrice'] = stopPriceString || priceString;
+ }
+ if (amountEnum === 0) {
+ request['parameters']['quantity'] = amountString;
+ } else {
+ request['parameters']['quoteOrderQuantity'] = amountString;
+ }
+ if (clientOrderId !== undefined) {
+ request['parameters']['clientOrderId'] = clientOrderId;
+ }
+ // {
+ // market: 'DIL-ETH',
+ // orderId: '7cdc8e90-eb7d-11ea-9e60-4118569f6e63',
+ // wallet: '0x0AB991497116f7F5532a4c2f4f7B1784488628e1',
+ // time: 1598873478650,
+ // status: 'filled',
+ // type: 'limit',
+ // side: 'buy',
+ // originalQuantity: '0.40000000',
+ // executedQuantity: '0.40000000',
+ // cumulativeQuoteQuantity: '0.03962396',
+ // price: '1.00000000',
+ // fills: [
+ // {
+ // fillId: '48582d10-b9bb-3c4b-94d3-e67537cf2472',
+ // price: '0.09905990',
+ // quantity: '0.40000000',
+ // quoteQuantity: '0.03962396',
+ // time: 1598873478650,
+ // makerSide: 'sell',
+ // sequence: 5053,
+ // fee: '0.00080000',
+ // feeAsset: 'DIL',
+ // gas: '0.00857497',
+ // liquidity: 'taker',
+ // txStatus: 'pending'
+ // }
+ // ],
+ // avgExecutionPrice: '0.09905990'
+ // }
+ // we don't use extend here because it is a signed endpoint
+ const response = await this.privatePostOrders (request);
+ return this.parseOrder (response, market);
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ this.checkRequiredCredentials ();
+ await this.loadMarkets ();
+ const nonce = this.uuidv1 ();
+ const amountString = this.currencyToPrecision (code, amount);
+ const currency = this.currency (code);
+ const walletBytes = this.remove0xPrefix (this.walletAddress);
+ const byteArray = [
+ this.base16ToBinary (nonce),
+ this.base16ToBinary (walletBytes),
+ this.stringToBinary (this.encode (currency['id'])),
+ this.stringToBinary (this.encode (amountString)),
+ this.numberToBE (1, 1), // bool set to true
+ ];
+ const binary = this.binaryConcatArray (byteArray);
+ const hash = this.hash (binary, 'keccak', 'hex');
+ const signature = this.signMessageString (hash, this.privateKey);
+ const request = {
+ 'parameters': {
+ 'nonce': nonce,
+ 'wallet': address,
+ 'asset': currency['id'],
+ 'quantity': amountString,
+ },
+ 'signature': signature,
+ };
+ // {
+ // withdrawalId: 'a61dcff0-ec4d-11ea-8b83-c78a6ecb3180',
+ // asset: 'ETH',
+ // assetContractAddress: '0x0000000000000000000000000000000000000000',
+ // quantity: '0.20000000',
+ // time: 1598962883190,
+ // fee: '0.00024000',
+ // txStatus: 'pending',
+ // txId: null
+ // }
+ const response = await this.privatePostWithdrawals (request);
+ const id = this.safeString (response, 'withdrawalId');
+ return {
+ 'info': response,
+ 'id': id,
+ };
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ this.checkRequiredCredentials ();
+ await this.loadMarkets ();
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ const nonce = this.uuidv1 ();
+ const walletBytes = this.remove0xPrefix (this.walletAddress);
+ const byteArray = [
+ this.base16ToBinary (nonce),
+ this.base16ToBinary (walletBytes),
+ this.stringToBinary (this.encode (id)),
+ ];
+ const binary = this.binaryConcatArray (byteArray);
+ const hash = this.hash (binary, 'keccak', 'hex');
+ const signature = this.signMessageString (hash, this.privateKey);
+ const request = {
+ 'parameters': {
+ 'nonce': nonce,
+ 'wallet': this.walletAddress,
+ 'orderId': id,
+ },
+ 'signature': signature,
+ };
+ // [ { orderId: '688336f0-ec50-11ea-9842-b332f8a34d0e' } ]
+ const response = await this.privateDeleteOrders (this.extend (request, params));
+ const canceledOrder = this.safeValue (response, 0);
+ return this.parseOrder (canceledOrder, market);
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ const errorCode = this.safeString (response, 'code');
+ const message = this.safeString (response, 'message');
+ if (errorCode in this.exceptions) {
+ const Exception = this.exceptions[errorCode];
+ throw new Exception (this.id + ' ' + message);
+ }
+ if (errorCode !== undefined) {
+ throw new ExchangeError (this.id + ' ' + message);
+ }
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ params = this.extend ({
+ 'method': 'privateGetDeposits',
+ }, params);
+ return this.fetchTransactionsHelper (code, since, limit, params);
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ params = this.extend ({
+ 'method': 'privateGetWithdrawals',
+ }, params);
+ return this.fetchTransactionsHelper (code, since, limit, params);
+ }
+
+ async fetchTransactionsHelper (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const nonce = this.uuidv1 ();
+ const request = {
+ 'nonce': nonce,
+ 'wallet': this.walletAddress,
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['asset'] = currency['id'];
+ }
+ if (since !== undefined) {
+ request['start'] = since;
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ // [
+ // {
+ // depositId: 'e9970cc0-eb6b-11ea-9e89-09a5ebc1f98e',
+ // asset: 'ETH',
+ // quantity: '1.00000000',
+ // txId: '0xcd4aac3171d7131cc9e795568c67938675185ac17641553ef54c8a7c294c8142',
+ // txTime: 1598865853000,
+ // confirmationTime: 1598865930231
+ // }
+ // ]
+ const method = params['method'];
+ params = this.omit (params, 'method');
+ const response = await this[method] (this.extend (request, params));
+ return this.parseTransactions (response, currency, since, limit);
+ }
+
+ parseTransactionStatus (status) {
+ const statuses = {
+ 'mined': 'ok',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ // fetchDeposits
+ // {
+ // depositId: 'e9970cc0-eb6b-11ea-9e89-09a5ebc1f98f',
+ // asset: 'ETH',
+ // quantity: '1.00000000',
+ // txId: '0xcd4aac3171d7131cc9e795568c67938675185ac17641553ef54c8a7c294c8142',
+ // txTime: 1598865853000,
+ // confirmationTime: 1598865930231
+ // }
+ // fetchWithdrwalas
+ // {
+ // withdrawalId: 'a62d8760-ec4d-11ea-9fa6-47904c19499b',
+ // asset: 'ETH',
+ // assetContractAddress: '0x0000000000000000000000000000000000000000',
+ // quantity: '0.20000000',
+ // time: 1598962883288,
+ // fee: '0.00024000',
+ // txId: '0x305e9cdbaa85ad029f50578d13d31d777c085de573ed5334d95c19116d8c03ce',
+ // txStatus: 'mined'
+ // }
+ let type = undefined;
+ if ('depositId' in transaction) {
+ type = 'deposit';
+ } else if ('withdrawalId' in transaction) {
+ type = 'withdrawal';
+ }
+ const id = this.safeString2 (transaction, 'depositId', 'withdrawId');
+ const code = this.safeCurrencyCode (this.safeString (transaction, 'asset'), currency);
+ const amount = this.safeFloat (transaction, 'quantity');
+ const txid = this.safeString (transaction, 'txId');
+ const timestamp = this.safeInteger (transaction, 'txTime');
+ let fee = undefined;
+ if ('fee' in transaction) {
+ fee = {
+ 'cost': this.safeFloat (transaction, 'fee'),
+ 'currency': 'ETH',
+ };
+ }
+ const rawStatus = this.safeString (transaction, 'txStatus');
+ const status = this.parseTransactionStatus (rawStatus);
+ const updated = this.safeInteger (transaction, 'confirmationTime');
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'address': undefined,
+ 'tag': undefined,
+ 'type': type,
+ 'amount': amount,
+ 'currency': code,
+ 'status': status,
+ 'updated': updated,
+ 'fee': fee,
+ };
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const version = this.safeString (this.options, 'version', 'v1');
+ let url = this.urls['api'][api] + '/' + version + '/' + path;
+ const keys = Object.keys (params);
+ const length = keys.length;
+ let query = undefined;
+ if (length > 0) {
+ if (method === 'GET') {
+ query = this.urlencode (params);
+ url = url + '?' + query;
+ } else {
+ body = this.json (params);
+ }
+ }
+ headers = {
+ 'Content-Type': 'application/json',
+ };
+ if (this.apiKey !== undefined) {
+ headers['IDEX-API-Key'] = this.apiKey;
+ }
+ if (api === 'private') {
+ let payload = undefined;
+ if (method === 'GET') {
+ payload = query;
+ } else {
+ payload = body;
+ }
+ headers['IDEX-HMAC-Signature'] = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'hex');
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/independentreserve.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/independentreserve.js
similarity index 81%
rename from TaskServer/node_modules/ccxt/js/independentreserve.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/independentreserve.js
index 872ce0b05..30f75d9a6 100644
--- a/TaskServer/node_modules/ccxt/js/independentreserve.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/independentreserve.js
@@ -14,10 +14,21 @@ module.exports = class independentreserve extends Exchange {
'countries': [ 'AU', 'NZ' ], // Australia, New Zealand
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/30521662-cf3f477c-9bcb-11e7-89bc-d1ac85012eda.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87182090-1e9e9080-c2ec-11ea-8e49-563db9a38f37.jpg',
'api': {
'public': 'https://api.independentreserve.com/Public',
'private': 'https://api.independentreserve.com/Private',
@@ -177,6 +188,8 @@ module.exports = class independentreserve extends Exchange {
}
parseOrder (order, market = undefined) {
+ //
+ // fetchOrder
//
// {
// "OrderGuid": "c7347e4c-b865-4c94-8f74-d934d4b0b177",
@@ -192,9 +205,26 @@ module.exports = class independentreserve extends Exchange {
// "SecondaryCurrencyCode": "Usd"
// }
//
+ // fetchOpenOrders & fetchClosedOrders
+ //
+ // {
+ // "OrderGuid": "b8f7ad89-e4e4-4dfe-9ea3-514d38b5edb3",
+ // "CreatedTimestampUtc": "2020-09-08T03:04:18.616367Z",
+ // "OrderType": "LimitOffer",
+ // "Volume": 0.0005,
+ // "Outstanding": 0.0005,
+ // "Price": 113885.83,
+ // "AvgPrice": 113885.83,
+ // "Value": 56.94,
+ // "Status": "Open",
+ // "PrimaryCurrencyCode": "Xbt",
+ // "SecondaryCurrencyCode": "Usd",
+ // "FeePercent": 0.005,
+ // }
+ //
let symbol = undefined;
const baseId = this.safeString (order, 'PrimaryCurrencyCode');
- const quoteId = this.safeString (order, 'PrimaryCurrencyCode');
+ const quoteId = this.safeString (order, 'SecondaryCurrencyCode');
let base = undefined;
let quote = undefined;
if ((baseId !== undefined) && (quoteId !== undefined)) {
@@ -206,34 +236,36 @@ module.exports = class independentreserve extends Exchange {
base = market['base'];
quote = market['quote'];
}
- let orderType = this.safeValue (order, 'Type');
- if (orderType.indexOf ('Market') >= 0) {
- orderType = 'market';
- } else if (orderType.indexOf ('Limit') >= 0) {
- orderType = 'limit';
- }
+ let orderType = this.safeString2 (order, 'Type', 'OrderType');
let side = undefined;
if (orderType.indexOf ('Bid') >= 0) {
side = 'buy';
} else if (orderType.indexOf ('Offer') >= 0) {
side = 'sell';
}
+ if (orderType.indexOf ('Market') >= 0) {
+ orderType = 'market';
+ } else if (orderType.indexOf ('Limit') >= 0) {
+ orderType = 'limit';
+ }
const timestamp = this.parse8601 (this.safeString (order, 'CreatedTimestampUtc'));
- let amount = this.safeFloat (order, 'VolumeOrdered');
- if (amount === undefined) {
- amount = this.safeFloat (order, 'Volume');
+ const amount = this.safeFloat2 (order, 'VolumeOrdered', 'Volume');
+ let filled = this.safeFloat (order, 'VolumeFilled');
+ let remaining = this.safeFloat (order, 'Outstanding');
+ if (filled === undefined) {
+ if ((remaining !== undefined) && (amount !== undefined)) {
+ filled = Math.max (0, amount - remaining);
+ }
+ }
+ if (remaining === undefined) {
+ if ((filled !== undefined) && (amount !== undefined)) {
+ remaining = Math.max (0, amount - filled);
+ }
}
- const filled = this.safeFloat (order, 'VolumeFilled');
- let remaining = undefined;
const feeRate = this.safeFloat (order, 'FeePercent');
let feeCost = undefined;
- if (amount !== undefined) {
- if (filled !== undefined) {
- remaining = amount - filled;
- if (feeRate !== undefined) {
- feeCost = feeRate * filled;
- }
- }
+ if (feeRate !== undefined) {
+ feeCost = feeRate * filled;
}
const fee = {
'rate': feeRate,
@@ -254,8 +286,10 @@ module.exports = class independentreserve extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': orderType,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -292,6 +326,44 @@ module.exports = class independentreserve extends Exchange {
return this.parseOrder (response, market);
}
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = this.ordered ({});
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['primaryCurrencyCode'] = market['baseId'];
+ request['secondaryCurrencyCode'] = market['quoteId'];
+ }
+ if (limit === undefined) {
+ limit = 50;
+ }
+ request['pageIndex'] = 1;
+ request['pageSize'] = limit;
+ const response = await this.privatePostGetOpenOrders (this.extend (request, params));
+ const data = this.safeValue (response, 'Data', []);
+ return this.parseOrders (data, market, since, limit);
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = this.ordered ({});
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['primaryCurrencyCode'] = market['baseId'];
+ request['secondaryCurrencyCode'] = market['quoteId'];
+ }
+ if (limit === undefined) {
+ limit = 50;
+ }
+ request['pageIndex'] = 1;
+ request['pageSize'] = limit;
+ const response = await this.privatePostGetClosedOrders (this.extend (request, params));
+ const data = this.safeValue (response, 'Data', []);
+ return this.parseOrders (data, market, since, limit);
+ }
+
async fetchMyTrades (symbol = undefined, since = undefined, limit = 50, params = {}) {
await this.loadMarkets ();
const pageIndex = this.safeInteger (params, 'pageIndex', 1);
diff --git a/TaskServer/node_modules/ccxt/js/indodax.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/indodax.js
similarity index 51%
rename from TaskServer/node_modules/ccxt/js/indodax.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/indodax.js
index 42ee4051e..30457eca2 100644
--- a/TaskServer/node_modules/ccxt/js/indodax.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/indodax.js
@@ -14,31 +14,41 @@ module.exports = class indodax extends Exchange {
'name': 'INDODAX',
'countries': [ 'ID' ], // Indonesia
'has': {
+ 'cancelOrder': true,
'CORS': false,
'createMarketOrder': false,
- 'fetchTickers': false,
- 'fetchOrder': true,
- 'fetchOrders': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
- 'fetchOpenOrders': true,
- 'fetchMyTrades': false,
'fetchCurrencies': false,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': false,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchTicker': true,
+ 'fetchTickers': false,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'withdraw': true,
},
- 'version': '1.8', // as of 9 April 2018
+ 'version': '2.0', // as of 9 April 2018
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/37443283-2fddd0e4-281c-11e8-9741-b4f1419001b5.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87070508-9358c880-c221-11ea-8dc5-5391afbbb422.jpg',
'api': {
'public': 'https://indodax.com/api',
'private': 'https://indodax.com/tapi',
},
'www': 'https://www.indodax.com',
- 'doc': 'https://indodax.com/downloads/BITCOINCOID-API-DOCUMENTATION.pdf',
+ 'doc': 'https://github.com/btcid/indodax-official-api-docs',
'referral': 'https://indodax.com/ref/testbitcoincoid/1',
},
'api': {
'public': {
'get': [
+ 'server_time',
+ 'pairs',
'{pair}/ticker',
'{pair}/trades',
'{pair}/depth',
@@ -58,81 +68,6 @@ module.exports = class indodax extends Exchange {
],
},
},
- 'markets': {
- // HARDCODING IS DEPRECATED
- // but they don't have a corresponding endpoint in their API
- // IDR markets
- 'BTC/IDR': { 'id': 'btc_idr', 'symbol': 'BTC/IDR', 'base': 'BTC', 'quote': 'IDR', 'baseId': 'btc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.0001, 'max': undefined }}},
- 'TEN/IDR': { 'id': 'ten_idr', 'symbol': 'TEN/IDR', 'base': 'TEN', 'quote': 'IDR', 'baseId': 'ten', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'ABYSS/IDR': { 'id': 'abyss_idr', 'symbol': 'ABYSS/IDR', 'base': 'ABYSS', 'quote': 'IDR', 'baseId': 'abyss', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'ACT/IDR': { 'id': 'act_idr', 'symbol': 'ACT/IDR', 'base': 'ACT', 'quote': 'IDR', 'baseId': 'act', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'ADA/IDR': { 'id': 'ada_idr', 'symbol': 'ADA/IDR', 'base': 'ADA', 'quote': 'IDR', 'baseId': 'ada', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'AOA/IDR': { 'id': 'aoa_idr', 'symbol': 'AOA/IDR', 'base': 'AOA', 'quote': 'IDR', 'baseId': 'aoa', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'ATOM/IDR': { 'id': 'atom_idr', 'symbol': 'ATOM/IDR', 'base': 'ATOM', 'quote': 'IDR', 'baseId': 'atom', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'BAT/IDR': { 'id': 'bat_idr', 'symbol': 'BAT/IDR', 'base': 'BAT', 'quote': 'IDR', 'baseId': 'bat', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'BCD/IDR': { 'id': 'bcd_idr', 'symbol': 'BCD/IDR', 'base': 'BCD', 'quote': 'IDR', 'baseId': 'bcd', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'BCH/IDR': { 'id': 'bchabc_idr', 'symbol': 'BCH/IDR', 'base': 'BCH', 'quote': 'IDR', 'baseId': 'bchabc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.001, 'max': undefined }}},
- 'BSV/IDR': { 'id': 'bchsv_idr', 'symbol': 'BSV/IDR', 'base': 'BSV', 'quote': 'IDR', 'baseId': 'bchsv', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.001, 'max': undefined }}},
- 'BNB/IDR': { 'id': 'bnb_idr', 'symbol': 'BNB/IDR', 'base': 'BNB', 'quote': 'IDR', 'baseId': 'bnb', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.001, 'max': undefined }}},
- 'BTG/IDR': { 'id': 'btg_idr', 'symbol': 'BTG/IDR', 'base': 'BTG', 'quote': 'IDR', 'baseId': 'btg', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'BTS/IDR': { 'id': 'bts_idr', 'symbol': 'BTS/IDR', 'base': 'BTS', 'quote': 'IDR', 'baseId': 'bts', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'BTT/IDR': { 'id': 'btt_idr', 'symbol': 'BTT/IDR', 'base': 'BTT', 'quote': 'IDR', 'baseId': 'btt', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1000, 'max': undefined }}},
- 'COAL/IDR': { 'id': 'coal_idr', 'symbol': 'COAL/IDR', 'base': 'COAL', 'quote': 'IDR', 'baseId': 'coal', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 50, 'max': undefined }}},
- 'CRO/IDR': { 'id': 'cro_idr', 'symbol': 'CRO/IDR', 'base': 'CRO', 'quote': 'IDR', 'baseId': 'cro', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'DASH/IDR': { 'id': 'drk_idr', 'symbol': 'DASH/IDR', 'base': 'DASH', 'quote': 'IDR', 'baseId': 'drk', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'DAX/IDR': { 'id': 'dax_idr', 'symbol': 'DAX/IDR', 'base': 'DAX', 'quote': 'IDR', 'baseId': 'dax', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'DOGE/IDR': { 'id': 'doge_idr', 'symbol': 'DOGE/IDR', 'base': 'DOGE', 'quote': 'IDR', 'baseId': 'doge', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1000, 'max': undefined }}},
- 'ETH/IDR': { 'id': 'eth_idr', 'symbol': 'ETH/IDR', 'base': 'ETH', 'quote': 'IDR', 'baseId': 'eth', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'EOS/IDR': { 'id': 'eos_idr', 'symbol': 'EOS/IDR', 'base': 'EOS', 'quote': 'IDR', 'baseId': 'eos', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'ETC/IDR': { 'id': 'etc_idr', 'symbol': 'ETC/IDR', 'base': 'ETC', 'quote': 'IDR', 'baseId': 'etc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'GARD/IDR': { 'id': 'gard_idr', 'symbol': 'GARD/IDR', 'base': 'GARD', 'quote': 'IDR', 'baseId': 'gard', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'GSC/IDR': { 'id': 'gsc_idr', 'symbol': 'GSC/IDR', 'base': 'GSC', 'quote': 'IDR', 'baseId': 'gsc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'GXC/IDR': { 'id': 'gxs_idr', 'symbol': 'GXC/IDR', 'base': 'GXC', 'quote': 'IDR', 'baseId': 'gxs', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'HPB/IDR': { 'id': 'hpb_idr', 'symbol': 'HPB/IDR', 'base': 'HPB', 'quote': 'IDR', 'baseId': 'hpb', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'IGNIS/IDR': { 'id': 'ignis_idr', 'symbol': 'IGNIS/IDR', 'base': 'IGNIS', 'quote': 'IDR', 'baseId': 'ignis', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'INX/IDR': { 'id': 'inx_idr', 'symbol': 'INX/IDR', 'base': 'INX', 'quote': 'IDR', 'baseId': 'inx', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'IOTA/IDR': { 'id': 'iota_idr', 'symbol': 'IOTA/IDR', 'base': 'IOTA', 'quote': 'IDR', 'baseId': 'iota', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'LINK/IDR': { 'id': 'link_idr', 'symbol': 'LINK/IDR', 'base': 'LINK', 'quote': 'IDR', 'baseId': 'link', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'LTC/IDR': { 'id': 'ltc_idr', 'symbol': 'LTC/IDR', 'base': 'LTC', 'quote': 'IDR', 'baseId': 'ltc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'MBL/IDR': { 'id': 'mbl_idr', 'symbol': 'MBL/IDR', 'base': 'MBL', 'quote': 'IDR', 'baseId': 'mbl', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'NEO/IDR': { 'id': 'neo_idr', 'symbol': 'NEO/IDR', 'base': 'NEO', 'quote': 'IDR', 'baseId': 'neo', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'NPXS/IDR': { 'id': 'npxs_idr', 'symbol': 'NPXS/IDR', 'base': 'NPXS', 'quote': 'IDR', 'baseId': 'npxs', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'NXT/IDR': { 'id': 'nxt_idr', 'symbol': 'NXT/IDR', 'base': 'NXT', 'quote': 'IDR', 'baseId': 'nxt', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'OKB/IDR': { 'id': 'okb_idr', 'symbol': 'OKB/IDR', 'base': 'OKB', 'quote': 'IDR', 'baseId': 'okb', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.5, 'max': undefined }}},
- 'ONT/IDR': { 'id': 'ont_idr', 'symbol': 'ONT/IDR', 'base': 'ONT', 'quote': 'IDR', 'baseId': 'ont', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'PXG/IDR': { 'id': 'pxg_idr', 'symbol': 'PXG/IDR', 'base': 'PXG', 'quote': 'IDR', 'baseId': 'pxg', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'QTUM/IDR': { 'id': 'qtum_idr', 'symbol': 'QTUM/IDR', 'base': 'QTUM', 'quote': 'IDR', 'baseId': 'qtum', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'RVN/IDR': { 'id': 'rvn_idr', 'symbol': 'RVN/IDR', 'base': 'RVN', 'quote': 'IDR', 'baseId': 'rvn', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'SSP/IDR': { 'id': 'ssp_idr', 'symbol': 'SSP/IDR', 'base': 'SSP', 'quote': 'IDR', 'baseId': 'ssp', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- 'SUMO/IDR': { 'id': 'sumo_idr', 'symbol': 'SUMO/IDR', 'base': 'SUMO', 'quote': 'IDR', 'baseId': 'sumo', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 5, 'max': undefined }}},
- // 'STQ/IDR': { 'id': 'stq_idr', 'symbol': 'STQ/IDR', 'base': 'STQ', 'quote': 'IDR', 'baseId': 'stq', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'TRX/IDR': { 'id': 'trx_idr', 'symbol': 'TRX/IDR', 'base': 'TRX', 'quote': 'IDR', 'baseId': 'trx', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'USDC/IDR': { 'id': 'usdc_idr', 'symbol': 'USDC/IDR', 'base': 'USDC', 'quote': 'IDR', 'baseId': 'usdc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'USDT/IDR': { 'id': 'usdt_idr', 'symbol': 'USDT/IDR', 'base': 'USDT', 'quote': 'IDR', 'baseId': 'usdt', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'VEX/IDR': { 'id': 'vex_idr', 'symbol': 'VEX/IDR', 'base': 'VEX', 'quote': 'IDR', 'baseId': 'vex', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': undefined, 'max': undefined }}},
- 'VIDY/IDR': { 'id': 'vidy_idr', 'symbol': 'VIDY/IDR', 'base': 'VIDY', 'quote': 'IDR', 'baseId': 'vidy', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 100, 'max': undefined }}},
- 'WAVES/IDR': { 'id': 'waves_idr', 'symbol': 'WAVES/IDR', 'base': 'WAVES', 'quote': 'IDR', 'baseId': 'waves', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'XEM/IDR': { 'id': 'nem_idr', 'symbol': 'XEM/IDR', 'base': 'XEM', 'quote': 'IDR', 'baseId': 'nem', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'XLM/IDR': { 'id': 'str_idr', 'symbol': 'XLM/IDR', 'base': 'XLM', 'quote': 'IDR', 'baseId': 'str', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 20, 'max': undefined }}},
- 'XDCE/IDR': { 'id': 'xdce_idr', 'symbol': 'XDCE/IDR', 'base': 'XDCE', 'quote': 'IDR', 'baseId': 'xdce', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 10, 'max': undefined }}},
- 'XMR/IDR': { 'id': 'xmr_idr', 'symbol': 'XMR/IDR', 'base': 'XMR', 'quote': 'IDR', 'baseId': 'xmr', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'XRP/IDR': { 'id': 'xrp_idr', 'symbol': 'XRP/IDR', 'base': 'XRP', 'quote': 'IDR', 'baseId': 'xrp', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 10, 'max': undefined }}},
- 'XZC/IDR': { 'id': 'xzc_idr', 'symbol': 'XZC/IDR', 'base': 'XZC', 'quote': 'IDR', 'baseId': 'xzc', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'VSYS/IDR': { 'id': 'vsys_idr', 'symbol': 'VSYS/IDR', 'base': 'VSYS', 'quote': 'IDR', 'baseId': 'vsys', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.1, 'max': undefined }}},
- 'ZEC/IDR': { 'id': 'zec_idr', 'symbol': 'ZEC/IDR', 'base': 'ZEC', 'quote': 'IDR', 'baseId': 'zec', 'quoteId': 'idr', 'precision': { 'amount': 8, 'price': 0 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- // BTC markets
- 'BTS/BTC': { 'id': 'bts_btc', 'symbol': 'BTS/BTC', 'base': 'BTS', 'quote': 'BTC', 'baseId': 'bts', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'DASH/BTC': { 'id': 'drk_btc', 'symbol': 'DASH/BTC', 'base': 'DASH', 'quote': 'BTC', 'baseId': 'drk', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 6 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'DOGE/BTC': { 'id': 'doge_btc', 'symbol': 'DOGE/BTC', 'base': 'DOGE', 'quote': 'BTC', 'baseId': 'doge', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'ETH/BTC': { 'id': 'eth_btc', 'symbol': 'ETH/BTC', 'base': 'ETH', 'quote': 'BTC', 'baseId': 'eth', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 5 }, 'limits': { 'amount': { 'min': 0.001, 'max': undefined }}},
- 'LTC/BTC': { 'id': 'ltc_btc', 'symbol': 'LTC/BTC', 'base': 'LTC', 'quote': 'BTC', 'baseId': 'ltc', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 6 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'NXT/BTC': { 'id': 'nxt_btc', 'symbol': 'NXT/BTC', 'base': 'NXT', 'quote': 'BTC', 'baseId': 'nxt', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'SUMO/BTC': { 'id': 'sumo_btc', 'symbol': 'SUMO/BTC', 'base': 'SUMO', 'quote': 'BTC', 'baseId': 'sumo', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'TEN/BTC': { 'id': 'ten_btc', 'symbol': 'TEN/BTC', 'base': 'TEN', 'quote': 'BTC', 'baseId': 'ten', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'XEM/BTC': { 'id': 'nem_btc', 'symbol': 'XEM/BTC', 'base': 'XEM', 'quote': 'BTC', 'baseId': 'nem', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 1, 'max': undefined }}},
- 'XLM/BTC': { 'id': 'str_btc', 'symbol': 'XLM/BTC', 'base': 'XLM', 'quote': 'BTC', 'baseId': 'str', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- 'XRP/BTC': { 'id': 'xrp_btc', 'symbol': 'XRP/BTC', 'base': 'XRP', 'quote': 'BTC', 'baseId': 'xrp', 'quoteId': 'btc', 'precision': { 'amount': 8, 'price': 8 }, 'limits': { 'amount': { 'min': 0.01, 'max': undefined }}},
- },
'fees': {
'trading': {
'tierBased': false,
@@ -154,9 +89,121 @@ module.exports = class indodax extends Exchange {
'Minimum order': InvalidOrder,
},
},
+ // exchange-specific options
+ 'options': {
+ 'recvWindow': 5 * 1000, // default 5 sec
+ 'timeDifference': 0, // the difference between system clock and exchange clock
+ 'adjustForTimeDifference': false, // controls the adjustment logic upon instantiation
+ },
+ 'commonCurrencies': {
+ 'STR': 'XLM',
+ 'BCHABC': 'BCH',
+ 'BCHSV': 'BSV',
+ 'DRK': 'DASH',
+ 'NEM': 'XEM',
+ },
});
}
+ nonce () {
+ return this.milliseconds () - this.options['timeDifference'];
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetServerTime (params);
+ //
+ // {
+ // "timezone": "UTC",
+ // "server_time": 1571205969552
+ // }
+ //
+ return this.safeInteger (response, 'server_time');
+ }
+
+ async loadTimeDifference (params = {}) {
+ const serverTime = await this.fetchTime (params);
+ const after = this.milliseconds ();
+ this.options['timeDifference'] = after - serverTime;
+ return this.options['timeDifference'];
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetPairs (params);
+ //
+ // [
+ // {
+ // "id": "btcidr",
+ // "symbol": "BTCIDR",
+ // "base_currency": "idr",
+ // "traded_currency": "btc",
+ // "traded_currency_unit": "BTC",
+ // "description": "BTC/IDR",
+ // "ticker_id": "btc_idr",
+ // "volume_precision": 0,
+ // "price_precision": 1000,
+ // "price_round": 8,
+ // "pricescale": 1000,
+ // "trade_min_base_currency": 10000,
+ // "trade_min_traded_currency": 0.00007457,
+ // "has_memo": false,
+ // "memo_name": false,
+ // "has_payment_id": false,
+ // "trade_fee_percent": 0.3,
+ // "url_logo": "https://indodax.com/v2/logo/svg/color/btc.svg",
+ // "url_logo_png": "https://indodax.com/v2/logo/png/color/btc.png",
+ // "is_maintenance": 0
+ // }
+ // ]
+ //
+ const result = [];
+ for (let i = 0; i < response.length; i++) {
+ const market = response[i];
+ const id = this.safeString (market, 'ticker_id');
+ const baseId = this.safeString (market, 'traded_currency');
+ const quoteId = this.safeString (market, 'base_currency');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const taker = this.safeFloat (market, 'trade_fee_percent');
+ const isMaintenance = this.safeInteger (market, 'is_maintenance');
+ const active = (isMaintenance) ? false : true;
+ const pricePrecision = this.safeInteger (market, 'price_round');
+ const precision = {
+ 'amount': 8,
+ 'price': pricePrecision,
+ };
+ const limits = {
+ 'amount': {
+ 'min': this.safeFloat (market, 'trade_min_traded_currency'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': this.safeFloat (market, 'trade_min_base_currency'),
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ };
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'taker': taker,
+ 'percentage': true,
+ 'precision': precision,
+ 'limits': limits,
+ 'info': market,
+ 'active': active,
+ });
+ }
+ return result;
+ }
+
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.privatePostGetInfo (params);
@@ -279,6 +326,15 @@ module.exports = class indodax extends Exchange {
return this.parseTrades (response, market, since, limit);
}
+ parseOrderStatus (status) {
+ const statuses = {
+ 'open': 'open',
+ 'filled': 'closed',
+ 'cancelled': 'canceled',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
parseOrder (order, market = undefined) {
//
// {
@@ -294,12 +350,7 @@ module.exports = class indodax extends Exchange {
if ('type' in order) {
side = order['type'];
}
- let status = this.safeString (order, 'status', 'open');
- if (status === 'filled') {
- status = 'closed';
- } else if (status === 'cancelled') {
- status = 'canceled';
- }
+ const status = this.parseOrderStatus (this.safeString (order, 'status', 'open'));
let symbol = undefined;
let cost = undefined;
const price = this.safeFloat (order, 'price');
@@ -347,8 +398,10 @@ module.exports = class indodax extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -419,12 +472,9 @@ module.exports = class indodax extends Exchange {
request['pair'] = market['id'];
}
const response = await this.privatePostOrderHistory (this.extend (request, params));
- let orders = this.parseOrders (response['return']['orders'], market, since, limit);
+ let orders = this.parseOrders (response['return']['orders'], market);
orders = this.filterBy (orders, 'status', 'closed');
- if (symbol !== undefined) {
- return this.filterBySymbol (orders, symbol);
- }
- return orders;
+ return this.filterBySymbolSinceLimit (orders, symbol, since, limit);
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
@@ -446,9 +496,11 @@ module.exports = class indodax extends Exchange {
}
request[currency] = amount;
const result = await this.privatePostTrade (this.extend (request, params));
+ const data = this.safeValue (result, 'return', {});
+ const id = this.safeString (data, 'order_id');
return {
'info': result,
- 'id': result['return']['order_id'].toString (),
+ 'id': id,
};
}
@@ -524,7 +576,8 @@ module.exports = class indodax extends Exchange {
this.checkRequiredCredentials ();
body = this.urlencode (this.extend ({
'method': path,
- 'nonce': this.nonce (),
+ 'timestamp': this.nonce (),
+ 'recvWindow': this.options['recvWindow'],
}, params));
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
diff --git a/TaskServer/node_modules/ccxt/js/itbit.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/itbit.js
similarity index 96%
rename from TaskServer/node_modules/ccxt/js/itbit.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/itbit.js
index dacb3199f..f26cf47eb 100644
--- a/TaskServer/node_modules/ccxt/js/itbit.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/itbit.js
@@ -16,9 +16,20 @@ module.exports = class itbit extends Exchange {
'rateLimit': 2000,
'version': 'v1',
'has': {
+ 'cancelOrder': true,
'CORS': true,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/27822159-66153620-60ad-11e7-89e7-005f6d7f3de0.jpg',
@@ -67,6 +78,9 @@ module.exports = class itbit extends Exchange {
'ETH/USD': { 'id': 'ETHUSD', 'symbol': 'ETH/USD', 'base': 'ETH', 'quote': 'USD', 'baseId': 'ETH', 'quoteId': 'USD' },
'ETH/EUR': { 'id': 'ETHEUR', 'symbol': 'ETH/EUR', 'base': 'ETH', 'quote': 'EUR', 'baseId': 'ETH', 'quoteId': 'EUR' },
'ETH/SGD': { 'id': 'ETHSGD', 'symbol': 'ETH/SGD', 'base': 'ETH', 'quote': 'SGD', 'baseId': 'ETH', 'quoteId': 'SGD' },
+ 'PAXGUSD': { 'id': 'PAXGUSD', 'symbol': 'PAXG/USD', 'base': 'PAXG', 'quote': 'USD', 'baseId': 'PAXG', 'quoteId': 'USD' },
+ 'BCHUSD': { 'id': 'BCHUSD', 'symbol': 'BCH/USD', 'base': 'BCH', 'quote': 'USD', 'baseId': 'BCH', 'quoteId': 'USD' },
+ 'LTCUSD': { 'id': 'LTCUSD', 'symbol': 'LTC/USD', 'base': 'LTC', 'quote': 'USD', 'baseId': 'LTC', 'quoteId': 'USD' },
},
'fees': {
'trading': {
@@ -525,8 +539,10 @@ module.exports = class itbit extends Exchange {
'status': this.parseOrderStatus (this.safeString (order, 'status')),
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -615,7 +631,7 @@ module.exports = class itbit extends Exchange {
const binhash = this.binaryConcat (binaryUrl, hash);
const signature = this.hmac (binhash, this.encode (this.secret), 'sha512', 'base64');
headers = {
- 'Authorization': this.apiKey + ':' + this.decode (signature),
+ 'Authorization': this.apiKey + ':' + signature,
'Content-Type': 'application/json',
'X-Auth-Timestamp': timestamp,
'X-Auth-Nonce': nonce,
diff --git a/TaskServer/node_modules/ccxt/js/kraken.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/kraken.js
similarity index 89%
rename from TaskServer/node_modules/ccxt/js/kraken.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/kraken.js
index 20c36d198..78e997c6d 100644
--- a/TaskServer/node_modules/ccxt/js/kraken.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/kraken.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { BadSymbol, ExchangeNotAvailable, ArgumentsRequired, PermissionDenied, AuthenticationError, ExchangeError, OrderNotFound, DDoSProtection, InvalidNonce, InsufficientFunds, CancelPending, InvalidOrder, InvalidAddress, NotSupported } = require ('./base/errors');
+const { BadSymbol, ExchangeNotAvailable, ArgumentsRequired, PermissionDenied, AuthenticationError, ExchangeError, OrderNotFound, DDoSProtection, InvalidNonce, InsufficientFunds, CancelPending, InvalidOrder, InvalidAddress } = require ('./base/errors');
const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -19,24 +19,32 @@ module.exports = class kraken extends Exchange {
'certified': true,
'pro': true,
'has': {
+ 'cancelOrder': true,
+ 'CORS': false,
'createDepositAddress': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchLedger': true,
+ 'fetchLedgerEntry': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrderTrades': 'emulated',
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
- 'CORS': false,
- 'fetchCurrencies': true,
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'fetchMyTrades': true,
'fetchWithdrawals': true,
- 'fetchDeposits': true,
'withdraw': true,
- 'fetchLedgerEntry': true,
- 'fetchLedger': true,
- 'fetchOrderTrades': 'emulated',
},
'marketsByAltname': {},
'timeframes': {
@@ -150,7 +158,6 @@ module.exports = class kraken extends Exchange {
'get': [
// we should really refrain from putting fixed fee numbers and stop hardcoding
// we will be using their web APIs to scrape all numbers from these articles
- '205893708', // -What-is-the-minimum-order-size-
'360000292886', // -What-are-the-deposit-fees-
'201893608', // -What-are-the-withdrawal-fees-
],
@@ -200,6 +207,8 @@ module.exports = class kraken extends Exchange {
'commonCurrencies': {
'XBT': 'BTC',
'XDG': 'DOGE',
+ 'REPV2': 'REP',
+ 'REP': 'REPV1',
},
'options': {
'cacheDepositMethodsOnFetchDepositAddress': true, // will issue up to two calls in fetchDepositAddress
@@ -207,7 +216,6 @@ module.exports = class kraken extends Exchange {
'delistedMarketsById': {},
// cannot withdraw/deposit these
'inactiveCurrencies': [ 'CAD', 'USD', 'JPY', 'GBP' ],
- 'fetchMinOrderAmounts': true,
},
'exceptions': {
'EQuery:Invalid asset pair': BadSymbol, // {"error":["EQuery:Invalid asset pair"]}
@@ -223,6 +231,8 @@ module.exports = class kraken extends Exchange {
'EGeneral:Internal error': ExchangeNotAvailable,
'EGeneral:Temporary lockout': DDoSProtection,
'EGeneral:Permission denied': PermissionDenied,
+ 'EOrder:Unknown order': InvalidOrder,
+ 'EOrder:Order minimum not met': InvalidOrder,
},
});
}
@@ -235,34 +245,6 @@ module.exports = class kraken extends Exchange {
return this.decimalToPrecision (fee, TRUNCATE, this.markets[symbol]['precision']['amount'], DECIMAL_PLACES);
}
- async fetchMinOrderAmounts (params = {}) {
- const response = await this.zendeskGet205893708 (params);
- const article = this.safeValue (response, 'article');
- const html = this.safeString (article, 'body');
- const parts = html.split (' | ');
- const numParts = parts.length;
- if (numParts < 3) {
- throw new NotSupported (this.id + ' fetchMinOrderAmounts HTML page markup has changed: https://kraken.zendesk.com/api/v2/help_center/en-us/articles/205893708');
- }
- const result = {};
- // skip the part before the header and the header itself
- for (let i = 2; i < parts.length; i++) {
- const part = parts[i];
- const chunks = part.split (' | ');
- const amountAndCode = chunks[0];
- if (amountAndCode !== 'To Be Announced') {
- const pieces = amountAndCode.split (' ');
- const numPieces = pieces.length;
- if (numPieces === 2) {
- const amount = parseFloat (pieces[0]);
- const code = this.safeCurrencyCode (pieces[1]);
- result[code] = amount;
- }
- }
- }
- return result;
- }
-
async fetchMarkets (params = {}) {
const response = await this.publicGetAssetPairs (params);
//
@@ -306,16 +288,12 @@ module.exports = class kraken extends Exchange {
// ],
// "fee_volume_currency":"ZUSD",
// "margin_call":80,
- // "margin_stop":40
+ // "margin_stop":40,
+ // "ordermin": "1"
// },
// }
// }
//
- const fetchMinOrderAmounts = this.safeValue (this.options, 'fetchMinOrderAmounts', false);
- let limits = {};
- if (fetchMinOrderAmounts) {
- limits = await this.fetchMinOrderAmounts ();
- }
const keys = Object.keys (response['result']);
let result = [];
for (let i = 0; i < keys.length; i++) {
@@ -335,10 +313,7 @@ module.exports = class kraken extends Exchange {
'amount': market['lot_decimals'],
'price': market['pair_decimals'],
};
- let minAmount = Math.pow (10, -precision['amount']);
- if (base in limits) {
- minAmount = limits[base];
- }
+ const minAmount = this.safeFloat (market, 'ordermin');
result.push ({
'id': id,
'symbol': symbol,
@@ -575,8 +550,8 @@ module.exports = class kraken extends Exchange {
await this.loadMarkets ();
symbols = (symbols === undefined) ? this.symbols : symbols;
const marketIds = [];
- for (let i = 0; i < this.symbols.length; i++) {
- const symbol = this.symbols[i];
+ for (let i = 0; i < symbols.length; i++) {
+ const symbol = symbols[i];
const market = this.markets[symbol];
if (market['active'] && !market['darkpool']) {
marketIds.push (market['id']);
@@ -594,11 +569,9 @@ module.exports = class kraken extends Exchange {
const market = this.markets_by_id[id];
const symbol = market['symbol'];
const ticker = tickers[id];
- if (this.inArray (symbol, symbols)) {
- result[symbol] = this.parseTicker (ticker, market);
- }
+ result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -616,14 +589,26 @@ module.exports = class kraken extends Exchange {
return this.parseTicker (ticker, market);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1591475640,
+ // "0.02500",
+ // "0.02500",
+ // "0.02500",
+ // "0.02500",
+ // "0.02500",
+ // "9.12201000",
+ // 5
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
- parseFloat (ohlcv[6]),
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 6),
];
}
@@ -638,7 +623,21 @@ module.exports = class kraken extends Exchange {
request['since'] = parseInt ((since - 1) / 1000);
}
const response = await this.publicGetOHLC (this.extend (request, params));
- const ohlcvs = response['result'][market['id']];
+ //
+ // {
+ // "error":[],
+ // "result":{
+ // "XETHXXBT":[
+ // [1591475580,"0.02499","0.02499","0.02499","0.02499","0.00000","0.00000000",0],
+ // [1591475640,"0.02500","0.02500","0.02500","0.02500","0.02500","9.12201000",5],
+ // [1591475700,"0.02499","0.02499","0.02499","0.02499","0.02499","1.28681415",2],
+ // [1591475760,"0.02499","0.02499","0.02499","0.02499","0.02499","0.08800000",1],
+ // ],
+ // "last":1591517580
+ // }
+ // }
+ const result = this.safeValue (response, 'result', {});
+ const ohlcvs = this.safeValue (result, market['id'], []);
return this.parseOHLCVs (ohlcvs, market, timeframe, since, limit);
}
@@ -959,6 +958,11 @@ module.exports = class kraken extends Exchange {
'ordertype': type,
'volume': this.amountToPrecision (symbol, amount),
};
+ const clientOrderId = this.safeString2 (params, 'userref', 'clientOrderId');
+ const query = this.omit (params, [ 'userref', 'clientOrderId' ]);
+ if (clientOrderId !== undefined) {
+ request['userref'] = clientOrderId;
+ }
const priceIsDefined = (price !== undefined);
const marketOrder = (type === 'market');
const limitOrder = (type === 'limit');
@@ -966,35 +970,18 @@ module.exports = class kraken extends Exchange {
if (shouldIncludePrice) {
request['price'] = this.priceToPrecision (symbol, price);
}
- const response = await this.privatePostAddOrder (this.extend (request, params));
- let id = this.safeValue (response['result'], 'txid');
- if (id !== undefined) {
- if (Array.isArray (id)) {
- const length = id.length;
- id = (length > 1) ? id : id[0];
- }
- }
- const clientOrderId = this.safeString (params, 'userref');
- return {
- 'id': id,
- 'clientOrderId': clientOrderId,
- 'info': response,
- 'timestamp': undefined,
- 'datetime': undefined,
- 'lastTradeTimestamp': undefined,
- 'symbol': symbol,
- 'type': type,
- 'side': side,
- 'price': price,
- 'amount': amount,
- 'cost': undefined,
- 'average': undefined,
- 'filled': undefined,
- 'remaining': undefined,
- 'status': undefined,
- 'fee': undefined,
- 'trades': undefined,
- };
+ const response = await this.privatePostAddOrder (this.extend (request, query));
+ //
+ // {
+ // error: [],
+ // result: {
+ // descr: { order: 'buy 0.02100000 ETHUSDT @ limit 330.00' },
+ // txid: [ 'OEKVV2-IH52O-TPL6GZ' ]
+ // }
+ // }
+ //
+ const result = this.safeValue (response, 'result');
+ return this.parseOrder (result);
}
findMarketByAltnameOrId (id) {
@@ -1055,10 +1042,32 @@ module.exports = class kraken extends Exchange {
}
parseOrder (order, market = undefined) {
+ //
+ // createOrder
+ //
+ // {
+ // descr: { order: 'buy 0.02100000 ETHUSDT @ limit 330.00' },
+ // txid: [ 'OEKVV2-IH52O-TPL6GZ' ]
+ // }
+ //
const description = this.safeValue (order, 'descr', {});
- const side = this.safeString (description, 'type');
- const type = this.safeString (description, 'ordertype');
- const marketId = this.safeString (description, 'pair');
+ const orderDescription = this.safeString (description, 'order');
+ let side = undefined;
+ let type = undefined;
+ let marketId = undefined;
+ let price = undefined;
+ let amount = undefined;
+ if (orderDescription !== undefined) {
+ const parts = orderDescription.split (' ');
+ side = this.safeString (parts, 0);
+ amount = this.safeFloat (parts, 1);
+ marketId = this.safeString (parts, 2);
+ type = this.safeString (parts, 4);
+ price = this.safeFloat (parts, 5);
+ }
+ side = this.safeString (description, 'type', side);
+ type = this.safeString (description, 'ordertype', type);
+ marketId = this.safeString (description, 'pair', marketId);
const foundMarket = this.findMarketByAltnameOrId (marketId);
let symbol = undefined;
if (foundMarket !== undefined) {
@@ -1068,16 +1077,19 @@ module.exports = class kraken extends Exchange {
market = this.getDelistedMarketById (marketId);
}
const timestamp = this.safeTimestamp (order, 'opentm');
- const amount = this.safeFloat (order, 'vol');
+ amount = this.safeFloat (order, 'vol', amount);
const filled = this.safeFloat (order, 'vol_exec');
- const remaining = amount - filled;
+ let remaining = undefined;
+ if ((amount !== undefined) && (filled !== undefined)) {
+ remaining = amount - filled;
+ }
let fee = undefined;
const cost = this.safeFloat (order, 'cost');
- let price = this.safeFloat (description, 'price');
- if ((price === undefined) || (price === 0)) {
+ price = this.safeFloat (description, 'price', price);
+ if ((price === undefined) || (price === 0.0)) {
price = this.safeFloat (description, 'price2');
}
- if ((price === undefined) || (price === 0)) {
+ if ((price === undefined) || (price === 0.0)) {
price = this.safeFloat (order, 'price', price);
}
const average = this.safeFloat (order, 'price');
@@ -1098,13 +1110,18 @@ module.exports = class kraken extends Exchange {
}
}
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- const id = this.safeString (order, 'id');
+ let id = this.safeString (order, 'id');
+ if (id === undefined) {
+ const txid = this.safeValue (order, 'txid');
+ id = this.safeString (txid, 0);
+ }
const clientOrderId = this.safeString (order, 'userref');
const rawTrades = this.safeValue (order, 'trades');
let trades = undefined;
if (rawTrades !== undefined) {
trades = this.parseTrades (rawTrades, market, undefined, undefined, { 'order': id });
}
+ const stopPrice = this.safeFloat (order, 'stopprice');
return {
'id': id,
'clientOrderId': clientOrderId,
@@ -1115,8 +1132,10 @@ module.exports = class kraken extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -1127,21 +1146,6 @@ module.exports = class kraken extends Exchange {
};
}
- parseOrders (orders, market = undefined, since = undefined, limit = undefined, params = {}) {
- const result = [];
- const ids = Object.keys (orders);
- let symbol = undefined;
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- for (let i = 0; i < ids.length; i++) {
- const id = ids[i];
- const order = this.extend ({ 'id': id }, orders[id]);
- result.push (this.extend (this.parseOrder (order, market), params));
- }
- return this.filterBySymbolSinceLimit (result, symbol, since, limit);
- }
-
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
const clientOrderId = this.safeValue2 (params, 'userref', 'clientOrderId');
@@ -1328,11 +1332,11 @@ module.exports = class kraken extends Exchange {
for (let i = 0; i < ids.length; i++) {
trades[ids[i]]['id'] = ids[i];
}
- const result = this.parseTrades (trades, undefined, since, limit);
- if (symbol === undefined) {
- return result;
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
}
- return this.filterBySymbol (result, symbol);
+ return this.parseTrades (trades, market, since, limit);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -1360,11 +1364,13 @@ module.exports = class kraken extends Exchange {
request['start'] = parseInt (since / 1000);
}
const response = await this.privatePostOpenOrders (this.extend (request, params));
- const orders = this.parseOrders (response['result']['open'], undefined, since, limit);
- if (symbol === undefined) {
- return orders;
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
}
- return this.filterBySymbol (orders, symbol);
+ const result = this.safeValue (response, 'result', {});
+ const orders = this.safeValue (result, 'open', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -1374,11 +1380,52 @@ module.exports = class kraken extends Exchange {
request['start'] = parseInt (since / 1000);
}
const response = await this.privatePostClosedOrders (this.extend (request, params));
- const orders = this.parseOrders (response['result']['closed'], undefined, since, limit);
- if (symbol === undefined) {
- return orders;
+ //
+ // {
+ // "error":[],
+ // "result":{
+ // "closed":{
+ // "OETZYO-UL524-QJMXCT":{
+ // "refid":null,
+ // "userref":null,
+ // "status":"canceled",
+ // "reason":"User requested",
+ // "opentm":1601489313.3898,
+ // "closetm":1601489346.5507,
+ // "starttm":0,
+ // "expiretm":0,
+ // "descr":{
+ // "pair":"ETHUSDT",
+ // "type":"buy",
+ // "ordertype":"limit",
+ // "price":"330.00",
+ // "price2":"0",
+ // "leverage":"none",
+ // "order":"buy 0.02100000 ETHUSDT @ limit 330.00",
+ // "close":""
+ // },
+ // "vol":"0.02100000",
+ // "vol_exec":"0.00000000",
+ // "cost":"0.00000",
+ // "fee":"0.00000",
+ // "price":"0.00000",
+ // "stopprice":"0.00000",
+ // "limitprice":"0.00000",
+ // "misc":"",
+ // "oflags":"fciq"
+ // },
+ // },
+ // "count":16
+ // }
+ // }
+ //
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
}
- return this.filterBySymbol (orders, symbol);
+ const result = this.safeValue (response, 'result', {});
+ const orders = this.safeValue (result, 'closed', []);
+ return this.parseOrders (orders, market, since, limit);
}
async fetchDepositMethods (code, params = {}) {
@@ -1388,7 +1435,7 @@ module.exports = class kraken extends Exchange {
'asset': currency['id'],
};
const response = await this.privatePostDepositMethods (this.extend (request, params));
- return response['result'];
+ return this.safeValue (response, 'result');
}
parseTransactionStatus (status) {
@@ -1505,6 +1552,22 @@ module.exports = class kraken extends Exchange {
return this.parseTransactionsByType ('deposit', response['result'], code, since, limit);
}
+ async fetchTime (params = {}) {
+ // https://www.kraken.com/en-us/features/api#get-server-time
+ const response = await this.publicGetTime (params);
+ //
+ // {
+ // "error": [],
+ // "result": {
+ // "unixtime": 1591502873,
+ // "rfc1123": "Sun, 7 Jun 20 04:07:53 +0000"
+ // }
+ // }
+ //
+ const result = this.safeValue (response, 'result', {});
+ return this.safeTimestamp (result, 'unixtime');
+ }
+
async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
// https://www.kraken.com/en-us/help/api#withdraw-status
if (code === undefined) {
@@ -1620,7 +1683,7 @@ module.exports = class kraken extends Exchange {
const signature = this.hmac (binhash, secret, 'sha512', 'base64');
headers = {
'API-Key': this.apiKey,
- 'API-Sign': this.decode (signature),
+ 'API-Sign': signature,
'Content-Type': 'application/x-www-form-urlencoded',
};
} else {
diff --git a/TaskServer/node_modules/ccxt/js/kucoin.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/kucoin.js
similarity index 92%
rename from TaskServer/node_modules/ccxt/js/kucoin.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/kucoin.js
index 025d0dc1e..84a9bebe8 100644
--- a/TaskServer/node_modules/ccxt/js/kucoin.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/kucoin.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, AccountSuspended, InvalidNonce, NotSupported, BadRequest, AuthenticationError, BadSymbol, RateLimitExceeded } = require ('./base/errors');
+const { ExchangeError, ArgumentsRequired, ExchangeNotAvailable, InsufficientFunds, OrderNotFound, InvalidOrder, AccountSuspended, InvalidNonce, NotSupported, BadRequest, AuthenticationError, BadSymbol, RateLimitExceeded, PermissionDenied } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -20,6 +20,7 @@ module.exports = class kucoin extends Exchange {
'comment': 'Platform 2.0',
'has': {
'CORS': false,
+ 'fetchStatus': true,
'fetchTime': true,
'fetchMarkets': true,
'fetchCurrencies': true,
@@ -45,7 +46,7 @@ module.exports = class kucoin extends Exchange {
'fetchLedger': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/57369448-3cc3aa80-7196-11e9-883e-5ebeb35e4f57.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295558-132aaf80-c50e-11ea-9801-a2fb0c57c799.jpg',
'referral': 'https://www.kucoin.com/?rcode=E5wkqe',
'api': {
'public': 'https://openapi-v2.kucoin.com',
@@ -123,7 +124,7 @@ module.exports = class kucoin extends Exchange {
'margin/lend/trade/settled',
'margin/lend/assets',
'margin/market',
- 'margin/margin/trade/last',
+ 'margin/trade/last',
],
'post': [
'accounts',
@@ -177,8 +178,9 @@ module.exports = class kucoin extends Exchange {
'404': NotSupported,
'405': NotSupported,
'429': RateLimitExceeded,
- '500': ExchangeError,
+ '500': ExchangeNotAvailable, // Internal Server Error -- We had a problem with our server. Try again later.
'503': ExchangeNotAvailable,
+ '101030': PermissionDenied, // {"code":"101030","msg":"You haven't yet enabled the margin trading"}
'200004': InsufficientFunds,
'230003': InsufficientFunds, // {"code":"230003","msg":"Balance insufficient!"}
'260100': InsufficientFunds, // {"code":"260100","msg":"account.noBalance"}
@@ -199,6 +201,7 @@ module.exports = class kucoin extends Exchange {
},
'broad': {
'Exceeded the access frequency': RateLimitExceeded,
+ 'require more permission': PermissionDenied,
},
},
'fees': {
@@ -232,6 +235,7 @@ module.exports = class kucoin extends Exchange {
'versions': {
'public': {
'GET': {
+ 'status': 'v1',
'market/orderbook/level{level}': 'v1',
'market/orderbook/level2': 'v2',
'market/orderbook/level2_20': 'v1',
@@ -253,8 +257,8 @@ module.exports = class kucoin extends Exchange {
return this.milliseconds ();
}
- async loadTimeDifference () {
- const response = await this.publicGetTimestamp ();
+ async loadTimeDifference (params = {}) {
+ const response = await this.publicGetTimestamp (params);
const after = this.milliseconds ();
const kucoinTime = this.safeInteger (response, 'data');
this.options['timeDifference'] = parseInt (after - kucoinTime);
@@ -273,6 +277,29 @@ module.exports = class kucoin extends Exchange {
return this.safeInteger (response, 'data');
}
+ async fetchStatus (params = {}) {
+ const response = await this.publicGetStatus (params);
+ //
+ // {
+ // "code":"200000",
+ // "data":{
+ // "msg":"",
+ // "status":"open"
+ // }
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ let status = this.safeValue (data, 'status');
+ if (status !== undefined) {
+ status = (status === 'open') ? 'ok' : 'maintenance';
+ this.status = this.extend (this.status, {
+ 'status': status,
+ 'updated': this.milliseconds (),
+ });
+ }
+ return this.status;
+ }
+
async fetchMarkets (params = {}) {
const response = await this.publicGetSymbols (params);
//
@@ -344,10 +371,17 @@ module.exports = class kucoin extends Exchange {
const response = await this.publicGetCurrencies (params);
//
// {
- // precision: 10,
- // name: 'KCS',
- // fullName: 'KCS shares',
- // currency: 'KCS'
+ // "currency": "OMG",
+ // "name": "OMG",
+ // "fullName": "OmiseGO",
+ // "precision": 8,
+ // "confirms": 12,
+ // "withdrawalMinSize": "4",
+ // "withdrawalMinFee": "1.25",
+ // "isWithdrawEnabled": false,
+ // "isDepositEnabled": false,
+ // "isMarginEnabled": false,
+ // "isDebitEnabled": false
// }
//
const responseData = response['data'];
@@ -358,14 +392,18 @@ module.exports = class kucoin extends Exchange {
const name = this.safeString (entry, 'fullName');
const code = this.safeCurrencyCode (id);
const precision = this.safeInteger (entry, 'precision');
+ const isWithdrawEnabled = this.safeValue (entry, 'isWithdrawEnabled', false);
+ const isDepositEnabled = this.safeValue (entry, 'isDepositEnabled', false);
+ const fee = this.safeFloat (entry, 'withdrawalMinFee');
+ const active = (isWithdrawEnabled && isDepositEnabled);
result[code] = {
'id': id,
'name': name,
'code': code,
'precision': precision,
'info': entry,
- 'active': undefined,
- 'fee': undefined,
+ 'active': active,
+ 'fee': fee,
'limits': this.limits,
};
}
@@ -475,24 +513,11 @@ module.exports = class kucoin extends Exchange {
percentage = percentage * 100;
}
const last = this.safeFloat2 (ticker, 'last', 'lastTradedPrice');
- let symbol = undefined;
const marketId = this.safeString (ticker, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
+ const baseVolume = this.safeFloat (ticker, 'vol');
+ const quoteVolume = this.safeFloat (ticker, 'volValue');
+ const vwap = this.vwap (baseVolume, quoteVolume);
const timestamp = this.safeInteger2 (ticker, 'time', 'datetime');
return {
'symbol': symbol,
@@ -504,7 +529,7 @@ module.exports = class kucoin extends Exchange {
'bidVolume': undefined,
'ask': this.safeFloat (ticker, 'sell'),
'askVolume': undefined,
- 'vwap': undefined,
+ 'vwap': vwap,
'open': this.safeFloat (ticker, 'open'),
'close': last,
'last': last,
@@ -512,8 +537,8 @@ module.exports = class kucoin extends Exchange {
'change': this.safeFloat (ticker, 'changePrice'),
'percentage': percentage,
'average': this.safeFloat (ticker, 'averagePrice'),
- 'baseVolume': this.safeFloat (ticker, 'vol'),
- 'quoteVolume': this.safeFloat (ticker, 'volValue'),
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
'info': ticker,
};
}
@@ -551,7 +576,7 @@ module.exports = class kucoin extends Exchange {
result[symbol] = ticker;
}
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -581,7 +606,7 @@ module.exports = class kucoin extends Exchange {
return this.parseTicker (response['data'], market);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// [
// "1545904980", // Start time of the candle cycle
@@ -594,12 +619,12 @@ module.exports = class kucoin extends Exchange {
// ]
//
return [
- parseInt (ohlcv[0]) * 1000,
- parseFloat (ohlcv[1]),
- parseFloat (ohlcv[3]),
- parseFloat (ohlcv[4]),
- parseFloat (ohlcv[2]),
- parseFloat (ohlcv[5]),
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -629,8 +654,18 @@ module.exports = class kucoin extends Exchange {
}
request['endAt'] = parseInt (Math.floor (endAt / 1000));
const response = await this.publicGetMarketCandles (this.extend (request, params));
- const responseData = this.safeValue (response, 'data', []);
- return this.parseOHLCVs (responseData, market, timeframe, since, limit);
+ //
+ // {
+ // "code":"200000",
+ // "data":[
+ // ["1591517700","0.025078","0.025069","0.025084","0.025064","18.9883256","0.4761861079404"],
+ // ["1591516800","0.025089","0.025079","0.025089","0.02506","99.4716622","2.494143499081"],
+ // ["1591515900","0.025079","0.02509","0.025091","0.025068","59.83701271","1.50060885172798"],
+ // ]
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
}
async createDepositAddress (code, params = {}) {
@@ -686,7 +721,7 @@ module.exports = class kucoin extends Exchange {
async fetchOrderBook (symbol, limit = undefined, params = {}) {
const level = this.safeInteger (params, 'level', 2);
let levelLimit = level.toString ();
- if (level === '2') {
+ if (levelLimit === '2') {
if (limit !== undefined) {
if ((limit !== 20) && (limit !== 100)) {
throw new ExchangeError (this.id + ' fetchOrderBook limit argument must be undefined, 20 or 100');
@@ -753,9 +788,10 @@ module.exports = class kucoin extends Exchange {
await this.loadMarkets ();
const marketId = this.marketId (symbol);
// required param, cannot be used twice
- const clientOid = this.uuid ();
+ const clientOrderId = this.safeString2 (params, 'clientOid', 'clientOrderId', this.uuid ());
+ params = this.omit (params, [ 'clientOid', 'clientOrderId' ]);
const request = {
- 'clientOid': clientOid,
+ 'clientOid': clientOrderId,
'side': side,
'symbol': marketId,
'type': type,
@@ -782,21 +818,26 @@ module.exports = class kucoin extends Exchange {
//
const data = this.safeValue (response, 'data', {});
const timestamp = this.milliseconds ();
+ const id = this.safeString (data, 'orderId');
const order = {
- 'id': this.safeString (data, 'orderId'),
+ 'id': id,
+ 'clientOrderId': clientOrderId,
+ 'info': data,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
'side': side,
'price': price,
+ 'amount': undefined,
'cost': undefined,
+ 'average': undefined,
'filled': undefined,
'remaining': undefined,
- 'timestamp': timestamp,
- 'datetime': this.iso8601 (timestamp),
+ 'status': undefined,
'fee': undefined,
- 'status': 'open',
- 'clientOrderId': clientOid,
- 'info': data,
+ 'trades': undefined,
};
if (!this.safeValue (params, 'quoteAmount')) {
order['amount'] = amount;
@@ -885,6 +926,12 @@ module.exports = class kucoin extends Exchange {
async fetchOrder (id, symbol = undefined, params = {}) {
await this.loadMarkets ();
+ // a special case for undefined ids
+ // otherwise a wrong endpoint for all orders will be triggered
+ // https://github.com/ccxt/ccxt/issues/7234
+ if (id === undefined) {
+ throw new InvalidOrder (this.id + ' fetchOrder requires an order id');
+ }
const request = {
'orderId': id,
};
@@ -893,7 +940,7 @@ module.exports = class kucoin extends Exchange {
market = this.market (symbol);
}
const response = await this.privateGetOrdersOrderId (this.extend (request, params));
- const responseData = response['data'];
+ const responseData = this.safeValue (response, 'data');
return this.parseOrder (responseData, market);
}
@@ -933,25 +980,8 @@ module.exports = class kucoin extends Exchange {
// "createdAt": 1547026471000 // time
// }
//
- let symbol = undefined;
const marketId = this.safeString (order, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- market = this.safeValue (this.markets_by_id, marketId);
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const orderId = this.safeString (order, 'id');
const type = this.safeString (order, 'type');
const timestamp = this.safeInteger (order, 'createdAt');
@@ -966,8 +996,10 @@ module.exports = class kucoin extends Exchange {
const cost = this.safeFloat (order, 'dealFunds');
const remaining = amount - filled;
// bool
- let status = order['isActive'] ? 'open' : 'closed';
- status = order['cancelExist'] ? 'canceled' : status;
+ const isActive = this.safeValue (order, 'isActive', false);
+ const cancelExist = this.safeValue (order, 'cancelExist', false);
+ let status = isActive ? 'open' : 'closed';
+ status = cancelExist ? 'canceled' : status;
const fee = {
'currency': feeCurrency,
'cost': feeCost,
@@ -982,14 +1014,18 @@ module.exports = class kucoin extends Exchange {
}
}
const clientOrderId = this.safeString (order, 'clientOid');
+ const timeInForce = this.safeString (order, 'timeInForce');
+ const stopPrice = this.safeFloat (order, 'stopPrice');
return {
'id': orderId,
'clientOrderId': clientOrderId,
'symbol': symbol,
'type': type,
+ 'timeInForce': timeInForce,
'side': side,
'amount': amount,
'price': price,
+ 'stopPrice': stopPrice,
'cost': cost,
'filled': filled,
'remaining': remaining,
@@ -1197,24 +1233,8 @@ module.exports = class kucoin extends Exchange {
// "id":"5c4d389e4c8c60413f78e2e5",
// }
//
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- const [ baseId, quoteId ] = marketId.split ('-');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market, '-');
const id = this.safeString2 (trade, 'tradeId', 'id');
const orderId = this.safeString (trade, 'orderId');
const takerOrMaker = this.safeString (trade, 'liquidity');
@@ -1247,7 +1267,10 @@ module.exports = class kucoin extends Exchange {
'rate': this.safeFloat (trade, 'feeRate'),
};
}
- const type = this.safeString (trade, 'type');
+ let type = this.safeString (trade, 'type');
+ if (type === 'match') {
+ type = undefined;
+ }
let cost = this.safeFloat2 (trade, 'funds', 'dealValue');
if (cost === undefined) {
if (amount !== undefined) {
@@ -1755,7 +1778,16 @@ module.exports = class kucoin extends Exchange {
}, headers);
const payload = timestamp + method + endpoint + endpart;
const signature = this.hmac (this.encode (payload), this.encode (this.secret), 'sha256', 'base64');
- headers['KC-API-SIGN'] = this.decode (signature);
+ headers['KC-API-SIGN'] = signature;
+ const partner = this.safeValue (this.options, 'partner', {});
+ const partnerId = this.safeString (partner, 'id');
+ const partnerSecret = this.safeString (partner, 'secret');
+ if ((partnerId !== undefined) && (partnerSecret !== undefined)) {
+ const partnerPayload = timestamp + partnerId + this.apiKey;
+ const partnerSignature = this.hmac (this.encode (partnerPayload), this.encode (partnerSecret), 'sha256', 'base64');
+ headers['KC-API-PARTNER-SIGN'] = partnerSignature;
+ headers['KC-API-PARTNER'] = partnerId;
+ }
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
diff --git a/TaskServer/node_modules/ccxt/js/kuna.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/kuna.js
similarity index 97%
rename from TaskServer/node_modules/ccxt/js/kuna.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/kuna.js
index d688a838c..8b80f40a4 100644
--- a/TaskServer/node_modules/ccxt/js/kuna.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/kuna.js
@@ -26,7 +26,7 @@ module.exports = class kuna extends acx {
'timeframes': undefined,
'urls': {
'referral': 'https://kuna.io?r=kunaid-gvfihe8az7o4',
- 'logo': 'https://user-images.githubusercontent.com/1294454/31697638-912824fa-b3c1-11e7-8c36-cf9606eb94ac.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87153927-f0578b80-c2c0-11ea-84b6-74612568e9e1.jpg',
'api': 'https://kuna.io',
'www': 'https://kuna.io',
'doc': 'https://kuna.io/documents/api',
@@ -60,7 +60,7 @@ module.exports = class kuna extends acx {
}
async fetchMarkets (params = {}) {
- const quotes = [ 'btc', 'eth', 'eurs', 'rub', 'uah', 'usd', 'usdt' ];
+ const quotes = [ 'btc', 'eth', 'eurs', 'rub', 'uah', 'usd', 'usdt', 'gol' ];
const pricePrecisions = {
'UAH': 0,
};
@@ -146,7 +146,7 @@ module.exports = class kuna extends acx {
'ask': 'sell',
'bid': 'buy',
};
- side = this.safeString (sideMap, side);
+ side = this.safeString (sideMap, side, side);
}
const price = this.safeFloat (trade, 'price');
const amount = this.safeFloat (trade, 'volume');
@@ -193,10 +193,10 @@ module.exports = class kuna extends acx {
return this.parseTrades (response, market, since, limit);
}
- async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limits = undefined, params = {}) {
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
- const trades = await this.fetchTrades (symbol, since, limits, params);
- const ohlcvc = this.buildOHLCVC (trades, timeframe, since, limits);
+ const trades = await this.fetchTrades (symbol, since, limit, params);
+ const ohlcvc = this.buildOHLCVC (trades, timeframe, since, limit);
const result = [];
for (let i = 0; i < ohlcvc.length; i++) {
const ohlcv = ohlcvc[i];
diff --git a/TaskServer/node_modules/ccxt/js/lakebtc.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/lakebtc.js
similarity index 95%
rename from TaskServer/node_modules/ccxt/js/lakebtc.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/lakebtc.js
index 4f62ae834..8acd8cc41 100644
--- a/TaskServer/node_modules/ccxt/js/lakebtc.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/lakebtc.js
@@ -16,9 +16,16 @@ module.exports = class lakebtc extends Exchange {
'version': 'api_v2',
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': true,
'createMarketOrder': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
'fetchTickers': true,
+ 'fetchTrades': true,
},
'urls': {
'logo': 'https://user-images.githubusercontent.com/1294454/28074120-72b7c38a-6660-11e7-92d9-d9027502281d.jpg',
@@ -157,16 +164,13 @@ module.exports = class lakebtc extends Exchange {
const ids = Object.keys (response);
const result = {};
for (let i = 0; i < ids.length; i++) {
- let symbol = ids[i];
- const ticker = response[symbol];
- let market = undefined;
- if (symbol in this.markets_by_id) {
- market = this.markets_by_id[symbol];
- symbol = market['symbol'];
- }
+ const marketId = ids[i];
+ const ticker = response[marketId];
+ const market = this.safeMarket (marketId);
+ const symbol = market['symbol'];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -294,7 +298,7 @@ module.exports = class lakebtc extends Exchange {
];
query = query.join ('&');
const signature = this.hmac (this.encode (query), this.encode (this.secret), 'sha1');
- const auth = this.encode (this.apiKey + ':' + signature);
+ const auth = this.apiKey + ':' + signature;
const signature64 = this.decode (this.stringToBase64 (auth));
headers = {
'Json-Rpc-Tonce': nonceAsString,
diff --git a/TaskServer/node_modules/ccxt/js/latoken.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/latoken.js
similarity index 98%
rename from TaskServer/node_modules/ccxt/js/latoken.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/latoken.js
index aedf173a1..f7e8b4a69 100644
--- a/TaskServer/node_modules/ccxt/js/latoken.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/latoken.js
@@ -350,14 +350,8 @@ module.exports = class latoken extends Exchange {
// "priceChange":-0.1500
// }
//
- let symbol = undefined;
const marketId = this.safeString (ticker, 'symbol');
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const open = this.safeFloat (ticker, 'open');
const close = this.safeFloat (ticker, 'close');
let change = undefined;
@@ -433,11 +427,9 @@ module.exports = class latoken extends Exchange {
for (let i = 0; i < response.length; i++) {
const ticker = this.parseTicker (response[i]);
const symbol = ticker['symbol'];
- if (symbols === undefined || this.inArray (symbol, symbols)) {
- result[symbol] = ticker;
- }
+ result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
parseTrade (trade, market = undefined) {
@@ -618,13 +610,7 @@ module.exports = class latoken extends Exchange {
const id = this.safeString (order, 'orderId');
const timestamp = this.safeTimestamp (order, 'timeCreated');
const marketId = this.safeString (order, 'symbol');
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const side = this.safeString (order, 'side');
const type = this.safeString (order, 'orderType');
const price = this.safeFloat (order, 'price');
@@ -659,8 +645,10 @@ module.exports = class latoken extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
diff --git a/TaskServer/node_modules/ccxt/js/lbank.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/lbank.js
similarity index 93%
rename from TaskServer/node_modules/ccxt/js/lbank.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/lbank.js
index 41df417f7..c90433927 100644
--- a/TaskServer/node_modules/ccxt/js/lbank.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/lbank.js
@@ -15,12 +15,20 @@ module.exports = class lbank extends Exchange {
'countries': [ 'CN' ],
'version': 'v1',
'has': {
- 'fetchTickers': true,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': false, // status 0 API doesn't work
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchMarkets': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': false, // status 0 API doesn't work
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': 'minute1',
@@ -103,6 +111,7 @@ module.exports = class lbank extends Exchange {
},
'commonCurrencies': {
'VET_ERC20': 'VEN',
+ 'PNT': 'Penta',
},
'options': {
'cacheSecretAsPem': true,
@@ -256,7 +265,7 @@ module.exports = class lbank extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchOrderBook (symbol, limit = 60, params = {}) {
@@ -324,14 +333,24 @@ module.exports = class lbank extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // [
+ // 1590969600,
+ // 0.02451657,
+ // 0.02452675,
+ // 0.02443701,
+ // 0.02447814,
+ // 238.38210000
+ // ]
+ //
return [
- ohlcv[0] * 1000,
- ohlcv[1],
- ohlcv[2],
- ohlcv[3],
- ohlcv[4],
- ohlcv[5],
+ this.safeTimestamp (ohlcv, 0),
+ this.safeFloat (ohlcv, 1),
+ this.safeFloat (ohlcv, 2),
+ this.safeFloat (ohlcv, 3),
+ this.safeFloat (ohlcv, 4),
+ this.safeFloat (ohlcv, 5),
];
}
@@ -351,6 +370,13 @@ module.exports = class lbank extends Exchange {
'time': parseInt (since / 1000),
};
const response = await this.publicGetKline (this.extend (request, params));
+ //
+ // [
+ // [1590969600,0.02451657,0.02452675,0.02443701,0.02447814,238.38210000],
+ // [1590969660,0.02447814,0.02449883,0.02443209,0.02445973,212.40270000],
+ // [1590969720,0.02445973,0.02452067,0.02445909,0.02446151,266.16920000],
+ // ]
+ //
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -459,8 +485,10 @@ module.exports = class lbank extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'amount': amount,
'filled': filled,
@@ -492,10 +520,7 @@ module.exports = class lbank extends Exchange {
order['order_type'] = type;
order['create_time'] = this.milliseconds ();
order['info'] = response;
- order = this.parseOrder (order, market);
- const id = order['id'];
- this.orders[id] = order;
- return order;
+ return this.parseOrder (order, market);
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -518,7 +543,8 @@ module.exports = class lbank extends Exchange {
'order_id': id,
};
const response = await this.privatePostOrdersInfo (this.extend (request, params));
- const orders = this.parseOrders (response['orders'], market);
+ const data = this.safeValue (response, 'orders', []);
+ const orders = this.parseOrders (data, market);
const numOrders = orders.length;
if (numOrders === 1) {
return orders[0];
@@ -539,7 +565,8 @@ module.exports = class lbank extends Exchange {
'page_length': limit,
};
const response = await this.privatePostOrdersInfoHistory (this.extend (request, params));
- return this.parseOrders (response['orders'], undefined, since, limit);
+ const data = this.safeValue (response, 'orders', []);
+ return this.parseOrders (data, undefined, since, limit);
}
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
@@ -565,7 +592,7 @@ module.exports = class lbank extends Exchange {
}
const response = this.privatePostWithdraw (this.extend (request, params));
return {
- 'id': response['id'],
+ 'id': this.safeString (response, 'id'),
'info': response,
};
}
diff --git a/TaskServer/node_modules/ccxt/js/liquid.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/liquid.js
similarity index 75%
rename from TaskServer/node_modules/ccxt/js/liquid.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/liquid.js
index 83e930a23..ddb1e0acc 100644
--- a/TaskServer/node_modules/ccxt/js/liquid.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/liquid.js
@@ -3,6 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
+const { TICK_SIZE } = require ('./base/functions/number');
const { ExchangeError, ArgumentsRequired, InvalidNonce, OrderNotFound, InvalidOrder, InsufficientFunds, AuthenticationError, DDoSProtection, NotSupported } = require ('./base/errors');
// ---------------------------------------------------------------------------
@@ -16,14 +17,22 @@ module.exports = class liquid extends Exchange {
'version': '2',
'rateLimit': 1000,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchCurrencies': true,
- 'fetchTickers': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'editOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'withdraw': true,
},
'urls': {
@@ -34,7 +43,7 @@ module.exports = class liquid extends Exchange {
'https://developers.liquid.com',
],
'fees': 'https://help.liquid.com/getting-started-with-liquid/the-platform/fee-structure',
- 'referral': 'https://www.liquid.com?affiliate=SbzC62lt30976',
+ 'referral': 'https://www.liquid.com/sign-up/?affiliate=SbzC62lt30976',
},
'api': {
'public': {
@@ -50,6 +59,7 @@ module.exports = class liquid extends Exchange {
},
'private': {
'get': [
+ 'accounts', // undocumented https://github.com/ccxt/ccxt/pull/7493
'accounts/balance',
'accounts/main_asset',
'accounts/{id}',
@@ -94,6 +104,77 @@ module.exports = class liquid extends Exchange {
],
},
},
+ 'fees': {
+ 'trading': {
+ 'tierBased': true,
+ 'percentage': true,
+ 'taker': 0.0015,
+ 'maker': 0.0000,
+ 'tiers': {
+ 'perpetual': {
+ 'maker': [
+ [ 0, 0.0000 ],
+ [ 25000, 0.0000 ],
+ [ 50000, -0.00025 ],
+ [ 100000, -0.00025 ],
+ [ 1000000, -0.00025 ],
+ [ 10000000, -0.00025 ],
+ [ 25000000, -0.00025 ],
+ [ 50000000, -0.00025 ],
+ [ 75000000, -0.00025 ],
+ [ 100000000, -0.00025 ],
+ [ 200000000, -0.00025 ],
+ [ 300000000, -0.00025 ],
+ ],
+ 'taker': [
+ [ 0, 0.000600 ],
+ [ 25000, 0.000575 ],
+ [ 50000, 0.000550 ],
+ [ 100000, 0.000525 ],
+ [ 1000000, 0.000500 ],
+ [ 10000000, 0.000475 ],
+ [ 25000000, 0.000450 ],
+ [ 50000000, 0.000425 ],
+ [ 75000000, 0.000400 ],
+ [ 100000000, 0.000375 ],
+ [ 200000000, 0.000350 ],
+ [ 300000000, 0.000325 ],
+ ],
+ },
+ 'spot': {
+ 'taker': [
+ [ 0, 0.0015 ],
+ [ 10000, 0.0015 ],
+ [ 20000, 0.0014 ],
+ [ 50000, 0.0013 ],
+ [ 100000, 0.0010 ],
+ [ 1000000, 0.0008 ],
+ [ 5000000, 0.0006 ],
+ [ 10000000, 0.0005 ],
+ [ 25000000, 0.0005 ],
+ [ 50000000, 0.00045 ],
+ [ 100000000, 0.0004 ],
+ [ 200000000, 0.0003 ],
+ ],
+ 'maker': [
+ [ 0, 0.0000 ],
+ [ 10000, 0.0015 ],
+ [ 20000, 0.1400 ],
+ [ 50000, 0.1300 ],
+ [ 100000, 0.0800 ],
+ [ 1000000, 0.0004 ],
+ [ 5000000, 0.00035 ],
+ [ 10000000, 0.00025 ],
+ [ 25000000, 0.0000 ],
+ [ 50000000, 0.0000 ],
+ [ 100000000, 0.0000 ],
+ [ 200000000, 0.0000 ],
+ ],
+ },
+ },
+ },
+ },
+ 'precisionMode': TICK_SIZE,
'exceptions': {
'API rate limit exceeded. Please retry after 300s': DDoSProtection,
'API Authentication failed': AuthenticationError,
@@ -104,10 +185,12 @@ module.exports = class liquid extends Exchange {
'not_enough_free_balance': InsufficientFunds,
'must_be_positive': InvalidOrder,
'less_than_order_size': InvalidOrder,
+ 'price_too_high': InvalidOrder,
},
'commonCurrencies': {
'WIN': 'WCOIN',
'HOT': 'HOT Token',
+ 'MIOTA': 'IOTA', // https://github.com/ccxt/ccxt/issues/7487
},
'options': {
'cancelOrderException': true,
@@ -145,6 +228,7 @@ module.exports = class liquid extends Exchange {
const amountPrecision = this.safeInteger (currency, 'display_precision');
const pricePrecision = this.safeInteger (currency, 'quoting_precision');
const precision = Math.max (amountPrecision, pricePrecision);
+ const decimalPrecision = 1 / Math.pow (10, precision);
result[code] = {
'id': id,
'code': code,
@@ -152,7 +236,7 @@ module.exports = class liquid extends Exchange {
'name': code,
'active': active,
'fee': this.safeFloat (currency, 'withdrawal_fee'),
- 'precision': precision,
+ 'precision': decimalPrecision,
'limits': {
'amount': {
'min': Math.pow (10, -amountPrecision),
@@ -181,30 +265,40 @@ module.exports = class liquid extends Exchange {
//
// [
// {
- // id: '7',
- // product_type: 'CurrencyPair',
- // code: 'CASH',
- // name: ' CASH Trading',
- // market_ask: 8865.79147,
- // market_bid: 8853.95988,
- // indicator: 1,
- // currency: 'SGD',
- // currency_pair_code: 'BTCSGD',
- // symbol: 'S$',
- // btc_minimum_withdraw: null,
- // fiat_minimum_withdraw: null,
- // pusher_channel: 'product_cash_btcsgd_7',
- // taker_fee: 0,
- // maker_fee: 0,
- // low_market_bid: '8803.25579',
- // high_market_ask: '8905.0',
- // volume_24h: '15.85443468',
- // last_price_24h: '8807.54625',
- // last_traded_price: '8857.77206',
- // last_traded_quantity: '0.00590974',
- // quoted_currency: 'SGD',
- // base_currency: 'BTC',
- // disabled: false,
+ // "id":"637",
+ // "product_type":"CurrencyPair",
+ // "code":"CASH",
+ // "name":null,
+ // "market_ask":"0.00000797",
+ // "market_bid":"0.00000727",
+ // "indicator":null,
+ // "currency":"BTC",
+ // "currency_pair_code":"TFTBTC",
+ // "symbol":null,
+ // "btc_minimum_withdraw":null,
+ // "fiat_minimum_withdraw":null,
+ // "pusher_channel":"product_cash_tftbtc_637",
+ // "taker_fee":"0.0",
+ // "maker_fee":"0.0",
+ // "low_market_bid":"0.00000685",
+ // "high_market_ask":"0.00000885",
+ // "volume_24h":"3696.0755956",
+ // "last_price_24h":"0.00000716",
+ // "last_traded_price":"0.00000766",
+ // "last_traded_quantity":"1748.0377978",
+ // "average_price":null,
+ // "quoted_currency":"BTC",
+ // "base_currency":"TFT",
+ // "tick_size":"0.00000001",
+ // "disabled":false,
+ // "margin_enabled":false,
+ // "cfd_enabled":false,
+ // "perpetual_enabled":false,
+ // "last_event_timestamp":"1596962820.000797146",
+ // "timestamp":"1596962820.000797146",
+ // "multiplier_up":"9.0",
+ // "multiplier_down":"0.1",
+ // "average_time_interval":null
// },
// ]
//
@@ -212,32 +306,44 @@ module.exports = class liquid extends Exchange {
//
// [
// {
- // "id": "603",
- // "product_type": "Perpetual",
- // "code": "CASH",
- // "name": null,
- // "market_ask": "1143900",
- // "market_bid": "1143250",
- // "currency": "JPY",
- // "currency_pair_code": "P-BTCJPY",
- // "pusher_channel": "product_cash_p-btcjpy_603",
- // "taker_fee": "0.0",
- // "maker_fee": "0.0",
- // "low_market_bid": "1124450.0",
- // "high_market_ask": "1151750.0",
- // "volume_24h": "0.1756",
- // "last_price_24h": "1129850.0",
- // "last_traded_price": "1144700.0",
- // "last_traded_quantity": "0.014",
- // "quoted_currency": "JPY",
- // "base_currency": "P-BTC",
- // "tick_size": "50.0",
- // "perpetual_enabled": true,
- // "index_price": "1142636.03935",
- // "mark_price": "1143522.18417",
- // "funding_rate": "0.00033",
- // "fair_price": "1143609.31009",
- // "timestamp": "1581558659.195353100",
+ // "id":"604",
+ // "product_type":"Perpetual",
+ // "code":"CASH",
+ // "name":null,
+ // "market_ask":"11721.5",
+ // "market_bid":"11719.0",
+ // "indicator":null,
+ // "currency":"USD",
+ // "currency_pair_code":"P-BTCUSD",
+ // "symbol":"$",
+ // "btc_minimum_withdraw":null,
+ // "fiat_minimum_withdraw":null,
+ // "pusher_channel":"product_cash_p-btcusd_604",
+ // "taker_fee":"0.0012",
+ // "maker_fee":"0.0",
+ // "low_market_bid":"11624.5",
+ // "high_market_ask":"11859.0",
+ // "volume_24h":"0.271",
+ // "last_price_24h":"11621.5",
+ // "last_traded_price":"11771.5",
+ // "last_traded_quantity":"0.09",
+ // "average_price":"11771.5",
+ // "quoted_currency":"USD",
+ // "base_currency":"P-BTC",
+ // "tick_size":"0.5",
+ // "disabled":false,
+ // "margin_enabled":false,
+ // "cfd_enabled":false,
+ // "perpetual_enabled":true,
+ // "last_event_timestamp":"1596963309.418853092",
+ // "timestamp":"1596963309.418853092",
+ // "multiplier_up":null,
+ // "multiplier_down":"0.1",
+ // "average_time_interval":300,
+ // "index_price":"11682.8124",
+ // "mark_price":"11719.96781",
+ // "funding_rate":"0.00273",
+ // "fair_price":"11720.2745"
// },
// ]
//
@@ -267,31 +373,22 @@ module.exports = class liquid extends Exchange {
} else {
symbol = base + '/' + quote;
}
- const maker = this.safeFloat (market, 'maker_fee');
- const taker = this.safeFloat (market, 'taker_fee');
+ let maker = this.fees['trading']['maker'];
+ let taker = this.fees['trading']['taker'];
+ if (type === 'swap') {
+ maker = this.safeFloat (market, 'maker_fee', this.fees['trading']['maker']);
+ taker = this.safeFloat (market, 'taker_fee', this.fees['trading']['taker']);
+ }
const disabled = this.safeValue (market, 'disabled', false);
const active = !disabled;
const baseCurrency = this.safeValue (currenciesByCode, base);
- const quoteCurrency = this.safeValue (currenciesByCode, quote);
const precision = {
- 'amount': 8,
- 'price': 8,
+ 'amount': 0.00000001,
+ 'price': this.safeFloat (market, 'tick_size'),
};
let minAmount = undefined;
if (baseCurrency !== undefined) {
minAmount = this.safeFloat (baseCurrency['info'], 'minimum_order_quantity');
- // precision['amount'] = this.safeInteger (baseCurrency['info'], 'quoting_precision');
- }
- let minPrice = undefined;
- if (quoteCurrency !== undefined) {
- precision['price'] = this.safeInteger (quoteCurrency['info'], 'quoting_precision');
- minPrice = Math.pow (10, -precision['price']);
- }
- let minCost = undefined;
- if (minPrice !== undefined) {
- if (minAmount !== undefined) {
- minCost = minPrice * minAmount;
- }
}
const limits = {
'amount': {
@@ -299,11 +396,11 @@ module.exports = class liquid extends Exchange {
'max': undefined,
},
'price': {
- 'min': minPrice,
+ 'min': undefined,
'max': undefined,
},
'cost': {
- 'min': minCost,
+ 'min': undefined,
'max': undefined,
},
};
@@ -330,21 +427,60 @@ module.exports = class liquid extends Exchange {
async fetchBalance (params = {}) {
await this.loadMarkets ();
- const response = await this.privateGetAccountsBalance (params);
+ const response = await this.privateGetAccounts (params);
//
- // [
- // {"currency":"USD","balance":"0.0"},
- // {"currency":"BTC","balance":"0.0"},
- // {"currency":"ETH","balance":"0.1651354"}
- // ]
+ // {
+ // crypto_accounts: [
+ // {
+ // id: 2221179,
+ // currency: 'USDT',
+ // balance: '0.0',
+ // reserved_balance: '0.0',
+ // pusher_channel: 'user_xxxxx_account_usdt',
+ // lowest_offer_interest_rate: null,
+ // highest_offer_interest_rate: null,
+ // address: '0',
+ // currency_symbol: 'USDT',
+ // minimum_withdraw: null,
+ // currency_type: 'crypto'
+ // },
+ // ],
+ // fiat_accounts: [
+ // {
+ // id: 1112734,
+ // currency: 'USD',
+ // balance: '0.0',
+ // reserved_balance: '0.0',
+ // pusher_channel: 'user_xxxxx_account_usd',
+ // lowest_offer_interest_rate: null,
+ // highest_offer_interest_rate: null,
+ // currency_symbol: '$',
+ // send_to_btc_address: null,
+ // exchange_rate: '1.0',
+ // currency_type: 'fiat'
+ // }
+ // ]
+ // }
//
const result = { 'info': response };
- for (let i = 0; i < response.length; i++) {
- const balance = response[i];
+ const crypto = this.safeValue (response, 'crypto_accounts', []);
+ const fiat = this.safeValue (response, 'fiat_accounts', []);
+ for (let i = 0; i < crypto.length; i++) {
+ const balance = crypto[i];
const currencyId = this.safeString (balance, 'currency');
const code = this.safeCurrencyCode (currencyId);
const account = this.account ();
account['total'] = this.safeFloat (balance, 'balance');
+ account['used'] = this.safeFloat (balance, 'reserved_balance');
+ result[code] = account;
+ }
+ for (let i = 0; i < fiat.length; i++) {
+ const balance = fiat[i];
+ const currencyId = this.safeString (balance, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['total'] = this.safeFloat (balance, 'balance');
+ account['used'] = this.safeFloat (balance, 'reserved_balance');
result[code] = account;
}
return this.parseBalance (result);
@@ -432,7 +568,7 @@ module.exports = class liquid extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -528,13 +664,18 @@ module.exports = class liquid extends Exchange {
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
await this.loadMarkets ();
+ const clientOrderId = this.safeString2 (params, 'clientOrderId', 'client_order_id');
+ params = this.omit (params, [ 'clientOrderId', 'client_order_id' ]);
const request = {
'order_type': type,
'product_id': this.marketId (symbol),
'side': side,
'quantity': this.amountToPrecision (symbol, amount),
};
- if (type === 'limit') {
+ if (clientOrderId !== undefined) {
+ request['client_order_id'] = clientOrderId;
+ }
+ if ((type === 'limit') || (type === 'limit_post_only') || (type === 'market_with_range') || (type === 'stop')) {
request['price'] = this.priceToPrecision (symbol, price);
}
const response = await this.privatePostOrders (this.extend (request, params));
@@ -557,7 +698,8 @@ module.exports = class liquid extends Exchange {
// "product_code": "CASH",
// "funding_currency": "USD",
// "currency_pair_code": "BTCUSD",
- // "order_fee": "0.0"
+ // "order_fee": "0.0",
+ // "client_order_id": null,
// }
//
return this.parseOrder (response);
@@ -626,6 +768,7 @@ module.exports = class liquid extends Exchange {
// "funding_currency": "USD",
// "currency_pair_code": "BTCUSD",
// "order_fee": "0.0"
+ // "client_order_id": null,
// }
//
// fetchOrder, fetchOrders, fetchOpenOrders, fetchClosedOrders
@@ -712,17 +855,20 @@ module.exports = class liquid extends Exchange {
remaining = amount - filled;
}
const side = this.safeString (order, 'side');
+ const clientOrderId = this.safeString (order, 'client_order_id');
return {
'id': orderId,
- 'clientOrderId': undefined,
+ 'clientOrderId': clientOrderId,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
'type': type,
+ 'timeInForce': undefined,
'status': status,
'symbol': symbol,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': filled,
'cost': cost,
@@ -927,10 +1073,12 @@ module.exports = class liquid extends Exchange {
const nonce = this.nonce ();
const request = {
'path': url,
- 'nonce': nonce,
'token_id': this.apiKey,
'iat': Math.floor (nonce / 1000), // issued at
};
+ if (!('client_order_id' in query)) {
+ request['nonce'] = nonce;
+ }
headers['X-Quoine-Auth'] = this.jwt (request, this.encode (this.secret));
} else {
if (Object.keys (query).length) {
diff --git a/TaskServer/node_modules/ccxt/js/livecoin.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/livecoin.js
similarity index 95%
rename from TaskServer/node_modules/ccxt/js/livecoin.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/livecoin.js
index eee90a7e2..0a8aa1aa0 100644
--- a/TaskServer/node_modules/ccxt/js/livecoin.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/livecoin.js
@@ -3,7 +3,7 @@
// ---------------------------------------------------------------------------
const Exchange = require ('./base/Exchange');
-const { ExchangeError, ArgumentsRequired, AuthenticationError, NotSupported, InvalidOrder, OrderNotFound, ExchangeNotAvailable, RateLimitExceeded, InsufficientFunds } = require ('./base/errors');
+const { ExchangeError, OnMaintenance, BadResponse, ArgumentsRequired, AuthenticationError, NotSupported, InvalidOrder, OrderNotFound, ExchangeNotAvailable, RateLimitExceeded, InsufficientFunds } = require ('./base/errors');
const { TRUNCATE, DECIMAL_PLACES } = require ('./base/functions/number');
// ---------------------------------------------------------------------------
@@ -17,18 +17,25 @@ module.exports = class livecoin extends Exchange {
'rateLimit': 1000,
'userAgent': this.userAgents['chrome'],
'has': {
+ 'cancelOrder': true,
+ 'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
'fetchDepositAddress': true,
'fetchDeposits': true,
- 'CORS': false,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
'fetchTickers': true,
- 'fetchCurrencies': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
- 'fetchOrders': true,
- 'fetchOrder': true,
- 'fetchOpenOrders': true,
- 'fetchClosedOrders': true,
- 'fetchMyTrades': true,
'fetchWithdrawals': true,
'withdraw': true,
},
@@ -91,19 +98,23 @@ module.exports = class livecoin extends Exchange {
},
},
'commonCurrencies': {
+ 'BIT': 'First Bitcoin',
'BTCH': 'Bithash',
'CPC': 'Capricoin',
+ 'CBC': 'CryptoBossCoin', // conflict with CBC (CashBet Coin)
'CPT': 'Cryptos', // conflict with CPT = Contents Protocol https://github.com/ccxt/ccxt/issues/4920 and https://github.com/ccxt/ccxt/issues/6081
'EDR': 'E-Dinar Coin', // conflicts with EDR for Endor Protocol and EDRCoin
'eETT': 'EETT',
'FirstBlood': '1ST',
'FORTYTWO': '42',
'LEO': 'LeoCoin',
+ 'MIOTA': 'IOTA', // https://github.com/ccxt/ccxt/issues/7487
'ORE': 'Orectic',
'PLN': 'Plutaneum', // conflict with Polish Zloty
'RUR': 'RUB',
'SCT': 'SpaceCoin',
'TPI': 'ThaneCoin',
+ 'UNUS': 'LEO', // https://github.com/ccxt/ccxt/issues/7496
'WAX': 'WAXP',
'wETT': 'WETT',
'XBT': 'Bricktox',
@@ -188,6 +199,13 @@ module.exports = class livecoin extends Exchange {
async fetchCurrencies (params = {}) {
const response = await this.publicGetInfoCoinInfo (params);
+ if (typeof response === 'string') {
+ if (response.indexOf ('site is under maintenance') >= 0) {
+ throw new OnMaintenance (this.id + ' fetchCurrencies() failed to fetch the currencies, the exchange is on maintenance');
+ } else {
+ throw new BadResponse (this.id + ' fetchCurrencies() failed to fetch the currencies');
+ }
+ }
const currencies = this.safeValue (response, 'info');
let result = {};
for (let i = 0; i < currencies.length; i++) {
@@ -375,12 +393,12 @@ module.exports = class livecoin extends Exchange {
const result = {};
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- const market = this.markets_by_id[id];
+ const market = this.safeMarket (id);
const symbol = market['symbol'];
const ticker = tickers[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -438,21 +456,8 @@ module.exports = class livecoin extends Exchange {
cost = amount * price;
}
}
- let symbol = undefined;
const marketId = this.safeString (trade, 'symbol');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- } else {
- const [ baseId, quoteId ] = marketId.split ('/');
- const base = this.safeCurrencyCode (baseId);
- const quote = this.safeCurrencyCode (quoteId);
- symbol = base + '/' + quote;
- }
- }
- if ((symbol === undefined) && (market !== undefined)) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market, '/');
return {
'id': id,
'info': trade,
@@ -577,14 +582,8 @@ module.exports = class livecoin extends Exchange {
// let trades = this.parseTrades (order['trades'], market, since, limit);
const trades = undefined;
const status = this.parseOrderStatus (this.safeString2 (order, 'status', 'orderStatus'));
- let symbol = undefined;
- if (market === undefined) {
- let marketId = this.safeString (order, 'currencyPair');
- marketId = this.safeString (order, 'symbol', marketId);
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- }
+ const marketId = this.safeString2 (order, 'symbol', 'currencyPair');
+ const symbol = this.safeSymbol (marketId, market, '/');
let type = this.safeStringLower (order, 'type');
let side = undefined;
if (type !== undefined) {
@@ -610,9 +609,11 @@ module.exports = class livecoin extends Exchange {
if (cost !== undefined && feeRate !== undefined) {
feeCost = cost * feeRate;
}
+ if ((market === undefined) && (symbol in this.markets)) {
+ market = this.markets[symbol];
+ }
let feeCurrency = undefined;
if (market !== undefined) {
- symbol = market['symbol'];
feeCurrency = market['quote'];
}
return {
@@ -625,8 +626,10 @@ module.exports = class livecoin extends Exchange {
'status': status,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'cost': cost,
'filled': filled,
diff --git a/TaskServer/node_modules/ccxt/js/luno.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/luno.js
similarity index 69%
rename from TaskServer/node_modules/ccxt/js/luno.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/luno.js
index 26538662a..068e1c184 100644
--- a/TaskServer/node_modules/ccxt/js/luno.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/luno.js
@@ -16,20 +16,29 @@ module.exports = class luno extends Exchange {
'rateLimit': 1000,
'version': '1',
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchTickers': true,
- 'fetchOrder': true,
- 'fetchOrders': true,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
+ 'fetchLedger': true,
+ 'fetchMarkets': true,
'fetchMyTrades': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
'fetchTradingFee': true,
'fetchTradingFees': true,
},
'urls': {
'referral': 'https://www.luno.com/invite/44893A',
'logo': 'https://user-images.githubusercontent.com/1294454/27766607-8c1a69d8-5ede-11e7-930c-540b5eb9be24.jpg',
- 'api': 'https://api.mybitx.com/api',
+ 'api': 'https://api.luno.com/api',
'www': 'https://www.luno.com',
'doc': [
'https://www.luno.com/en/api',
@@ -52,6 +61,7 @@ module.exports = class luno extends Exchange {
'accounts/{id}/pending',
'accounts/{id}/transactions',
'balance',
+ 'beneficiaries',
'fee_info',
'funding_address',
'listorders',
@@ -63,6 +73,7 @@ module.exports = class luno extends Exchange {
],
'post': [
'accounts',
+ 'accounts/{id}/name',
'postorder',
'marketorder',
'stoporder',
@@ -73,6 +84,7 @@ module.exports = class luno extends Exchange {
'oauth2/grant',
],
'put': [
+ 'accounts/{id}/name',
'quotes/{id}',
],
'delete': [
@@ -111,6 +123,25 @@ module.exports = class luno extends Exchange {
return result;
}
+ async fetchAccounts (params = {}) {
+ const response = await this.privateGetBalance (params);
+ const wallets = this.safeValue (response, 'balance', []);
+ const result = [];
+ for (let i = 0; i < wallets.length; i++) {
+ const account = wallets[i];
+ const accountId = this.safeString (account, 'account_id');
+ const currencyId = this.safeString (account, 'asset');
+ const code = this.safeCurrencyCode (currencyId);
+ result.push ({
+ 'id': accountId,
+ 'type': undefined,
+ 'currency': code,
+ 'info': account,
+ });
+ }
+ return result;
+ }
+
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.privateGetBalance (params);
@@ -147,6 +178,14 @@ module.exports = class luno extends Exchange {
return this.parseOrderBook (response, timestamp, 'bids', 'asks', 'price', 'volume');
}
+ parseOrderStatus (status) {
+ const statuses = {
+ // todo add other statuses
+ 'PENDING': 'open',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
parseOrder (order, market = undefined) {
//
// {
@@ -166,16 +205,11 @@ module.exports = class luno extends Exchange {
// }
//
const timestamp = this.safeInteger (order, 'creation_timestamp');
- const status = (order['state'] === 'PENDING') ? 'open' : 'closed';
+ let status = this.parseOrderStatus (this.safeString (order, 'state'));
+ status = (status === 'open') ? status : status;
const side = (order['type'] === 'ASK') ? 'sell' : 'buy';
const marketId = this.safeString (order, 'pair');
- let symbol = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const symbol = this.safeSymbol (marketId, market);
const price = this.safeFloat (order, 'limit_price');
const amount = this.safeFloat (order, 'limit_volume');
const quoteFee = this.safeFloat (order, 'fee_counter');
@@ -210,8 +244,10 @@ module.exports = class luno extends Exchange {
'status': status,
'symbol': symbol,
'type': undefined,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'amount': amount,
'filled': filled,
'cost': cost,
@@ -299,12 +335,12 @@ module.exports = class luno extends Exchange {
const result = {};
for (let i = 0; i < ids.length; i++) {
const id = ids[i];
- const market = this.markets_by_id[id];
+ const market = this.safeMarket (id);
const symbol = market['symbol'];
const ticker = tickers[id];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTicker (symbol, params = {}) {
@@ -452,6 +488,146 @@ module.exports = class luno extends Exchange {
return await this.privatePostStoporder (this.extend (request, params));
}
+ async fetchLedgerByEntries (code = undefined, entry = -1, limit = 1, params = {}) {
+ // by default without entry number or limit number, return most recent entry
+ const since = undefined;
+ const request = {
+ 'min_row': entry,
+ 'max_row': this.sum (entry, limit),
+ };
+ return await this.fetchLedger (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ await this.loadAccounts ();
+ let currency = undefined;
+ let id = this.safeString (params, 'id'); // account id
+ let min_row = this.safeValue (params, 'min_row');
+ let max_row = this.safeValue (params, 'max_row');
+ if (id === undefined) {
+ if (code === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchLedger() requires a currency code argument if no account id specified in params');
+ }
+ currency = this.currency (code);
+ const accountsByCurrencyCode = this.indexBy (this.accounts, 'currency');
+ const account = this.safeValue (accountsByCurrencyCode, code);
+ if (account === undefined) {
+ throw new ExchangeError (this.id + ' fetchLedger() could not find account id for ' + code);
+ }
+ id = account['id'];
+ }
+ if (min_row === undefined && max_row === undefined) {
+ max_row = 0; // Default to most recent transactions
+ min_row = -1000; // Maximum number of records supported
+ } else if (min_row === undefined || max_row === undefined) {
+ throw new ExchangeError (this.id + " fetchLedger() require both params 'max_row' and 'min_row' or neither to be defined");
+ }
+ if (limit !== undefined && max_row - min_row > limit) {
+ if (max_row <= 0) {
+ min_row = max_row - limit;
+ } else if (min_row > 0) {
+ max_row = min_row + limit;
+ }
+ }
+ if (max_row - min_row > 1000) {
+ throw new ExchangeError (this.id + " fetchLedger() requires the params 'max_row' - 'min_row' <= 1000");
+ }
+ const request = {
+ 'id': id,
+ 'min_row': min_row,
+ 'max_row': max_row,
+ };
+ const response = await this.privateGetAccountsIdTransactions (this.extend (params, request));
+ const entries = this.safeValue (response, 'transactions', []);
+ return this.parseLedger (entries, currency, since, limit);
+ }
+
+ parseLedgerComment (comment) {
+ const words = comment.split (' ');
+ const types = {
+ 'Withdrawal': 'fee',
+ 'Trading': 'fee',
+ 'Payment': 'transaction',
+ 'Sent': 'transaction',
+ 'Deposit': 'transaction',
+ 'Received': 'transaction',
+ 'Released': 'released',
+ 'Reserved': 'reserved',
+ 'Sold': 'trade',
+ 'Bought': 'trade',
+ 'Failure': 'failed',
+ };
+ let referenceId = undefined;
+ const firstWord = this.safeString (words, 0);
+ const thirdWord = this.safeString (words, 2);
+ const fourthWord = this.safeString (words, 3);
+ let type = this.safeString (types, firstWord, undefined);
+ if ((type === undefined) && (thirdWord === 'fee')) {
+ type = 'fee';
+ }
+ if ((type === 'reserved') && (fourthWord === 'order')) {
+ referenceId = this.safeString (words, 4);
+ }
+ return {
+ 'type': type,
+ 'referenceId': referenceId,
+ };
+ }
+
+ parseLedgerEntry (entry, currency = undefined) {
+ // const details = this.safeValue (entry, 'details', {});
+ const id = this.safeString (entry, 'row_index');
+ const account_id = this.safeString (entry, 'account_id');
+ const timestamp = this.safeValue (entry, 'timestamp');
+ const currencyId = this.safeString (entry, 'currency');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const available_delta = this.safeFloat (entry, 'available_delta');
+ const balance_delta = this.safeFloat (entry, 'balance_delta');
+ const after = this.safeFloat (entry, 'balance');
+ const comment = this.safeString (entry, 'description');
+ let before = after;
+ let amount = 0.0;
+ const result = this.parseLedgerComment (comment);
+ const type = result['type'];
+ const referenceId = result['referenceId'];
+ let direction = undefined;
+ let status = undefined;
+ if (balance_delta !== 0.0) {
+ before = after - balance_delta; // TODO: float precision
+ status = 'ok';
+ amount = Math.abs (balance_delta);
+ } else if (available_delta < 0.0) {
+ status = 'pending';
+ amount = Math.abs (available_delta);
+ } else if (available_delta > 0.0) {
+ status = 'canceled';
+ amount = Math.abs (available_delta);
+ }
+ if (balance_delta > 0 || available_delta > 0) {
+ direction = 'in';
+ } else if (balance_delta < 0 || available_delta < 0) {
+ direction = 'out';
+ }
+ return {
+ 'id': id,
+ 'direction': direction,
+ 'account': account_id,
+ 'referenceId': referenceId,
+ 'referenceAccount': undefined,
+ 'type': type,
+ 'currency': code,
+ 'amount': amount,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'before': before,
+ 'after': after,
+ 'status': status,
+ 'fee': undefined,
+ 'info': entry,
+ };
+ }
+
sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
let url = this.urls['api'] + '/' + this.version + '/' + this.implodeParams (path, params);
const query = this.omit (params, this.extractParams (path));
@@ -460,9 +636,10 @@ module.exports = class luno extends Exchange {
}
if (api === 'private') {
this.checkRequiredCredentials ();
- let auth = this.encode (this.apiKey + ':' + this.secret);
- auth = this.stringToBase64 (auth);
- headers = { 'Authorization': 'Basic ' + this.decode (auth) };
+ const auth = this.stringToBase64 (this.apiKey + ':' + this.secret);
+ headers = {
+ 'Authorization': 'Basic ' + this.decode (auth),
+ };
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
diff --git a/TaskServer/node_modules/ccxt/js/lykke.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/lykke.js
similarity index 69%
rename from TaskServer/node_modules/ccxt/js/lykke.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/lykke.js
index 2e69a172e..c513b8d80 100644
--- a/TaskServer/node_modules/ccxt/js/lykke.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/lykke.js
@@ -17,11 +17,32 @@ module.exports = class lykke extends Exchange {
'has': {
'CORS': false,
'fetchOHLCV': false,
- 'fetchTrades': true,
'fetchOpenOrders': true,
'fetchClosedOrders': true,
'fetchOrder': true,
'fetchOrders': true,
+ 'fetchTrades': true,
+ 'fetchMyTrades': true,
+ 'createOrder': true,
+ 'cancelOrder': true,
+ 'cancelAllOrders': true,
+ 'fetchBalance': true,
+ 'fetchMarkets': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ },
+ 'timeframes': {
+ '1m': 'Minute',
+ '5m': 'Min5',
+ '15m': 'Min15',
+ '30m': 'Min30',
+ '1h': 'Hour',
+ '4h': 'Hour4',
+ '6h': 'Hour6',
+ '12h': 'Hour12',
+ '1d': 'Day',
+ '1w': 'Week',
+ '1M': 'Month',
},
'requiredCredentials': {
'apiKey': true,
@@ -49,8 +70,26 @@ module.exports = class lykke extends Exchange {
'api': {
'mobile': {
'get': [
+ 'AssetPairs/rate',
+ 'AssetPairs/rate/{assetPairId}',
+ 'AssetPairs/dictionary/{market}',
+ 'Assets/dictionary',
+ 'Candles/history/{market}/available',
+ 'Candles/history/{market}/{assetPair}/{period}/{type}/{from}/{to}',
+ 'Company/ownershipStructure',
+ 'Company/registrationsCount',
+ 'IsAlive',
+ 'Market',
'Market/{market}',
+ 'Market/capitalization/{market}',
+ 'OrderBook',
+ 'OrderBook/{assetPairId}',
'Trades/{AssetPairId}',
+ 'Trades/Last/{assetPair}/{n}',
+ ],
+ 'post': [
+ 'AssetPairs/rate/history',
+ 'AssetPairs/rate/history/{assetPairId}',
],
},
'public': {
@@ -67,11 +106,20 @@ module.exports = class lykke extends Exchange {
'Orders',
'Orders/{id}',
'Wallets',
+ 'History/trades',
],
'post': [
'Orders/limit',
'Orders/market',
'Orders/{id}/Cancel',
+ 'Orders/v2/market',
+ 'Orders/v2/limit',
+ 'Orders/stoplimit',
+ 'Orders/bulk',
+ ],
+ 'delete': [
+ 'Orders',
+ 'Orders/{id}',
],
},
},
@@ -113,20 +161,45 @@ module.exports = class lykke extends Exchange {
// "action": "Buy"
// }
//
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (trade, 'AssetPairId');
- market = this.safeValue (this.markets_by_id, marketId);
+ // private fetchMyTrades
+ // {
+ // Id: '3500b83c-9963-4349-b3ee-b3e503073cea',
+ // OrderId: '83b50feb-8615-4dc6-b606-8a4168ecd708',
+ // DateTime: '2020-05-19T11:17:39.31+00:00',
+ // Timestamp: '2020-05-19T11:17:39.31+00:00',
+ // State: null,
+ // Amount: -0.004,
+ // BaseVolume: -0.004,
+ // QuotingVolume: 39.3898,
+ // Asset: 'BTC',
+ // BaseAssetId: 'BTC',
+ // QuotingAssetId: 'USD',
+ // AssetPair: 'BTCUSD',
+ // AssetPairId: 'BTCUSD',
+ // Price: 9847.427,
+ // Fee: { Amount: null, Type: 'Unknown', FeeAssetId: null }
+ // },
+ const marketId = this.safeString (trade, 'AssetPairId');
+ const symbol = this.safeSymbol (marketId, market);
+ const id = this.safeString2 (trade, 'id', 'Id');
+ const orderId = this.safeString (trade, 'OrderId');
+ const timestamp = this.parse8601 (this.safeString2 (trade, 'dateTime', 'DateTime'));
+ const price = this.safeFloat2 (trade, 'price', 'Price');
+ let amount = this.safeFloat2 (trade, 'volume', 'Amount');
+ let side = this.safeStringLower (trade, 'action');
+ if (side === undefined) {
+ if (amount < 0) {
+ side = 'sell';
+ } else {
+ side = 'buy';
+ }
}
- if (market) {
- symbol = market['symbol'];
- }
- const id = this.safeString (trade, 'id');
- const timestamp = this.parse8601 (this.safeString (trade, 'dateTime'));
- const side = this.safeStringLower (trade, 'action');
- const price = this.safeFloat (trade, 'price');
- const amount = this.safeFloat (trade, 'volume');
+ amount = Math.abs (amount);
const cost = price * amount;
+ const fee = {
+ 'cost': 0, // There are no fees for trading. https://www.lykke.com/wallet-fees-and-limits/
+ 'currency': market['quote'],
+ };
return {
'id': id,
'info': trade,
@@ -134,13 +207,13 @@ module.exports = class lykke extends Exchange {
'datetime': this.iso8601 (timestamp),
'symbol': symbol,
'type': undefined,
- 'order': undefined,
+ 'order': orderId,
'side': side,
'takerOrMaker': undefined,
'price': price,
'amount': amount,
'cost': cost,
- 'fee': undefined,
+ 'fee': fee,
};
}
@@ -159,6 +232,21 @@ module.exports = class lykke extends Exchange {
return this.parseTrades (response, market, since, limit);
}
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (limit !== undefined) {
+ request['take'] = limit; // How many maximum items have to be returned, max 1000 default 100.
+ }
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['assetPairId'] = market['id'];
+ }
+ const response = await this.privateGetHistoryTrades (this.extend (request, params));
+ return this.parseTrades (response, market, since, limit);
+ }
+
async fetchBalance (params = {}) {
await this.loadMarkets ();
const response = await this.privateGetWallets (params);
@@ -176,7 +264,19 @@ module.exports = class lykke extends Exchange {
}
async cancelOrder (id, symbol = undefined, params = {}) {
- return await this.privatePostOrdersIdCancel ({ 'id': id });
+ const request = { 'id': id };
+ return await this.privateDeleteOrdersId (this.extend (request, params));
+ }
+
+ async cancelAllOrders (symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {};
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['assetPairId'] = market['id'];
+ }
+ return await this.privateDeleteOrders (this.extend (request, params));
}
async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
@@ -186,17 +286,47 @@ module.exports = class lykke extends Exchange {
'AssetPairId': market['id'],
'OrderAction': this.capitalize (side),
'Volume': amount,
+ 'Asset': market['baseId'],
};
- if (type === 'market') {
- query['Asset'] = (side === 'buy') ? market['base'] : market['quote'];
- } else if (type === 'limit') {
+ if (type === 'limit') {
query['Price'] = price;
}
- const method = 'privatePostOrders' + this.capitalize (type);
+ const method = 'privatePostOrdersV2' + this.capitalize (type);
const result = await this[method] (this.extend (query, params));
+ //
+ // market
+ //
+ // {
+ // "Price": 0
+ // }
+ //
+ // limit
+ //
+ // {
+ // "Id":"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ // }
+ //
+ const id = this.safeString (result, 'Id');
+ price = this.safeFloat (result, 'Price');
return {
- 'id': undefined,
+ 'id': id,
'info': result,
+ 'clientOrderId': undefined,
+ 'timestamp': undefined,
+ 'datetime': undefined,
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': undefined,
+ 'average': undefined,
+ 'filled': undefined,
+ 'remaining': undefined,
+ 'status': undefined,
+ 'fee': undefined,
+ 'trades': undefined,
};
}
@@ -230,8 +360,8 @@ module.exports = class lykke extends Exchange {
const quote = this.safeCurrencyCode (quoteId);
const symbol = base + '/' + quote;
const precision = {
- 'amount': this.safeInteger (market, 'Accuracy'),
- 'price': this.safeInteger (market, 'InvertedAccuracy'),
+ 'price': this.safeInteger (market, 'Accuracy'),
+ 'amount': this.safeInteger (market, 'InvertedAccuracy'),
};
result.push ({
'id': id,
@@ -313,6 +443,7 @@ module.exports = class lykke extends Exchange {
'Cancelled': 'canceled',
'Rejected': 'rejected',
'Replaced': 'canceled',
+ 'Placed': 'open',
};
return this.safeString (statuses, status, status);
}
@@ -336,14 +467,8 @@ module.exports = class lykke extends Exchange {
// }
//
const status = this.parseOrderStatus (this.safeString (order, 'Status'));
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'AssetPairId');
- market = this.safeValue (this.markets_by_id, marketId);
- }
- if (market) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'AssetPairId');
+ const symbol = this.safeSymbol (marketId, market);
const lastTradeTimestamp = this.parse8601 (this.safeString (order, 'LastMatchTime'));
let timestamp = undefined;
if (('Registered' in order) && (order['Registered'])) {
@@ -352,8 +477,15 @@ module.exports = class lykke extends Exchange {
timestamp = this.parse8601 (order['CreatedAt']);
}
const price = this.safeFloat (order, 'Price');
- const amount = this.safeFloat (order, 'Volume');
- const remaining = this.safeFloat (order, 'RemainingVolume');
+ let side = undefined;
+ let amount = this.safeFloat (order, 'Volume');
+ if (amount < 0) {
+ side = 'sell';
+ amount = Math.abs (amount);
+ } else {
+ side = 'buy';
+ }
+ const remaining = Math.abs (this.safeFloat (order, 'RemainingVolume'));
const filled = amount - remaining;
const cost = filled * price;
const id = this.safeString (order, 'Id');
@@ -366,8 +498,10 @@ module.exports = class lykke extends Exchange {
'lastTradeTimestamp': lastTradeTimestamp,
'symbol': symbol,
'type': undefined,
- 'side': undefined,
+ 'timeInForce': undefined,
+ 'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': undefined,
'amount': amount,
@@ -391,25 +525,25 @@ module.exports = class lykke extends Exchange {
async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const response = await this.privateGetOrders (params);
- return this.parseOrders (response, undefined, since, limit);
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ return this.parseOrders (response, market, since, limit);
}
async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
const request = {
'status': 'InOrderBook',
};
- const response = await this.privateGetOrders (this.extend (request, params));
- return this.parseOrders (response, undefined, since, limit);
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
}
async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
- await this.loadMarkets ();
const request = {
'status': 'Matched',
};
- const response = await this.privateGetOrders (this.extend (request, params));
- return this.parseOrders (response, undefined, since, limit);
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
}
async fetchOrderBook (symbol, limit = undefined, params = {}) {
@@ -457,7 +591,7 @@ module.exports = class lykke extends Exchange {
url += '?' + this.urlencode (query);
}
} else if (api === 'private') {
- if (method === 'GET') {
+ if ((method === 'GET') || (method === 'DELETE')) {
if (Object.keys (query).length) {
url += '?' + this.urlencode (query);
}
diff --git a/TaskServer/node_modules/ccxt/js/mercado.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/mercado.js
similarity index 96%
rename from TaskServer/node_modules/ccxt/js/mercado.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/mercado.js
index 6be269e14..228e82f69 100644
--- a/TaskServer/node_modules/ccxt/js/mercado.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/mercado.js
@@ -16,15 +16,20 @@ module.exports = class mercado extends Exchange {
'rateLimit': 1000,
'version': 'v3',
'has': {
+ 'cancelOrder': true,
'CORS': true,
'createMarketOrder': true,
- 'fetchOrder': true,
- 'withdraw': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchOHLCV': true,
- 'fetchOrders': true,
'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
'fetchTicker': true,
'fetchTickers': false,
+ 'fetchTrades': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '1m',
@@ -91,6 +96,7 @@ module.exports = class mercado extends Exchange {
'BCH/BRL': { 'id': 'BRLBCH', 'symbol': 'BCH/BRL', 'base': 'BCH', 'quote': 'BRL', 'precision': { 'amount': 8, 'price': 5 }, 'suffix': 'BCash' },
'XRP/BRL': { 'id': 'BRLXRP', 'symbol': 'XRP/BRL', 'base': 'XRP', 'quote': 'BRL', 'precision': { 'amount': 8, 'price': 5 }, 'suffix': 'Ripple' },
'ETH/BRL': { 'id': 'BRLETH', 'symbol': 'ETH/BRL', 'base': 'ETH', 'quote': 'BRL', 'precision': { 'amount': 8, 'price': 5 }, 'suffix': 'Ethereum' },
+ 'USDC/BRL': { 'id': 'BRLUSDC', 'symbol': 'USDC/BRL', 'base': 'USDC', 'quote': 'BRL', 'precision': { 'amount': 8, 'price': 5 }, 'suffix': 'USDC' },
},
'fees': {
'trading': {
@@ -328,14 +334,8 @@ module.exports = class mercado extends Exchange {
side = (order['order_type'] === 1) ? 'buy' : 'sell';
}
const status = this.parseOrderStatus (this.safeString (order, 'status'));
- let symbol = undefined;
- if (market === undefined) {
- const marketId = this.safeString (order, 'coin_pair');
- market = this.safeValue (this.markets_by_id, marketId);
- }
- if (market !== undefined) {
- symbol = market['symbol'];
- }
+ const marketId = this.safeString (order, 'coin_pair');
+ market = this.safeMarket (marketId, market);
const timestamp = this.safeTimestamp (order, 'created_timestamp');
const fee = {
'cost': this.safeFloat (order, 'fee'),
@@ -356,10 +356,12 @@ module.exports = class mercado extends Exchange {
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
'lastTradeTimestamp': lastTradeTimestamp,
- 'symbol': symbol,
+ 'symbol': market['symbol'],
'type': 'limit',
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': undefined,
'cost': cost,
'average': average,
'amount': amount,
@@ -423,7 +425,7 @@ module.exports = class mercado extends Exchange {
};
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
return [
this.safeTimestamp (ohlcv, 'timestamp'),
this.safeFloat (ohlcv, 'open'),
diff --git a/TaskServer/node_modules/ccxt/js/mixcoins.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/mixcoins.js
similarity index 96%
rename from TaskServer/node_modules/ccxt/js/mixcoins.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/mixcoins.js
index 4bd5bc7e5..85138f138 100644
--- a/TaskServer/node_modules/ccxt/js/mixcoins.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/mixcoins.js
@@ -17,10 +17,16 @@ module.exports = class mixcoins extends Exchange {
'version': 'v1',
'userAgent': this.userAgents['chrome'],
'has': {
+ 'cancelOrder': true,
'CORS': false,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/30237212-ed29303c-9535-11e7-8af8-fcd381cfa20c.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87460810-1dd06c00-c616-11ea-9276-956f400d6ffa.jpg',
'api': 'https://mixcoins.com/api',
'www': 'https://mixcoins.com',
'doc': 'https://mixcoins.com/help/api/',
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/novadax.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/novadax.js
new file mode 100644
index 000000000..c02d4f1a9
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/novadax.js
@@ -0,0 +1,1188 @@
+'use strict';
+
+// ---------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { AuthenticationError, ExchangeError, PermissionDenied, BadRequest, CancelPending, OrderNotFound, InsufficientFunds, RateLimitExceeded, InvalidOrder, AccountSuspended, BadSymbol, OnMaintenance } = require ('./base/errors');
+const { TRUNCATE } = require ('./base/functions/number');
+
+// ---------------------------------------------------------------------------
+
+module.exports = class novadax extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'novadax',
+ 'name': 'NovaDAX',
+ 'countries': [ 'BR' ], // Brazil
+ 'rateLimit': 50,
+ 'version': 'v1',
+ // new metainfo interface
+ 'has': {
+ 'CORS': false,
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchAccounts': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrders': true,
+ 'fetchOrderTrades': true,
+ 'fetchOrderBook': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTime': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': true,
+ 'fetchWithdrawals': true,
+ 'withdraw': true,
+ },
+ 'timeframes': {
+ '1m': 'ONE_MIN',
+ '5m': 'FIVE_MIN',
+ '15m': 'FIFTEEN_MIN',
+ '30m': 'HALF_HOU',
+ '1h': 'ONE_HOU',
+ '1d': 'ONE_DAY',
+ '1w': 'ONE_WEE',
+ '1M': 'ONE_MON',
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/92337550-2b085500-f0b3-11ea-98e7-5794fb07dd3b.jpg',
+ 'api': {
+ 'public': 'https://api.novadax.com',
+ 'private': 'https://api.novadax.com',
+ },
+ 'www': 'https://www.novadax.com.br',
+ 'doc': [
+ 'https://doc.novadax.com/pt-BR/',
+ ],
+ 'fees': 'https://www.novadax.com.br/fees-and-limits',
+ 'referral': 'https://www.novadax.com.br/?s=ccxt',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'common/symbol',
+ 'common/symbols',
+ 'common/timestamp',
+ 'market/tickers',
+ 'market/ticker',
+ 'market/depth',
+ 'market/trades',
+ 'market/kline/history',
+ ],
+ },
+ 'private': {
+ 'get': [
+ 'orders/get',
+ 'orders/list',
+ 'orders/fill',
+ 'orders/fills',
+ 'account/getBalance',
+ 'account/subs',
+ 'account/subs/balance',
+ 'account/subs/transfer/record',
+ 'wallet/query/deposit-withdraw',
+ ],
+ 'post': [
+ 'orders/create',
+ 'orders/cancel',
+ 'account/withdraw/coin',
+ 'account/subs/transfer',
+ ],
+ },
+ },
+ 'fees': {
+ 'trading': {
+ 'tierBased': false,
+ 'percentage': true,
+ 'taker': 0.5 / 100,
+ 'maker': 0.3 / 100,
+ },
+ },
+ 'requiredCredentials': {
+ 'apiKey': true,
+ 'secret': true,
+ },
+ 'exceptions': {
+ 'exact': {
+ 'A99999': ExchangeError, // 500 Failed Internal error
+ // 'A10000': ExchangeError, // 200 Success Successful request
+ 'A10001': BadRequest, // 400 Params error Parameter is invalid
+ 'A10002': ExchangeError, // 404 Api not found API used is irrelevant
+ 'A10003': AuthenticationError, // 403 Authentication failed Authentication is failed
+ 'A10004': RateLimitExceeded, // 429 Too many requests Too many requests are made
+ 'A10005': PermissionDenied, // 403 Kyc required Need to complete KYC firstly
+ 'A10006': AccountSuspended, // 403 Customer canceled Account is canceled
+ 'A10007': BadRequest, // 400 Account not exist Sub account does not exist
+ 'A10011': BadSymbol, // 400 Symbol not exist Trading symbol does not exist
+ 'A10012': BadSymbol, // 400 Symbol not trading Trading symbol is temporarily not available
+ 'A10013': OnMaintenance, // 503 Symbol maintain Trading symbol is in maintain
+ 'A30001': OrderNotFound, // 400 Order not found Queried order is not found
+ 'A30002': InvalidOrder, // 400 Order amount is too small Order amount is too small
+ 'A30003': InvalidOrder, // 400 Order amount is invalid Order amount is invalid
+ 'A30004': InvalidOrder, // 400 Order value is too small Order value is too small
+ 'A30005': InvalidOrder, // 400 Order value is invalid Order value is invalid
+ 'A30006': InvalidOrder, // 400 Order price is invalid Order price is invalid
+ 'A30007': InsufficientFunds, // 400 Insufficient balance The balance is insufficient
+ 'A30008': InvalidOrder, // 400 Order was closed The order has been executed
+ 'A30009': InvalidOrder, // 400 Order canceled The order has been cancelled
+ 'A30010': CancelPending, // 400 Order cancelling The order is being cancelled
+ 'A30011': InvalidOrder, // 400 Order price too high The order price is too high
+ 'A30012': InvalidOrder, // 400 Order price too low The order price is too low
+ },
+ 'broad': {
+ },
+ },
+ 'options': {
+ 'fetchOHLCV': {
+ 'volume': 'amount', // 'amount' for base volume or 'vol' for quote volume
+ },
+ },
+ });
+ }
+
+ async fetchTime (params = {}) {
+ const response = await this.publicGetCommonTimestamp (params);
+ //
+ // {
+ // "code":"A10000",
+ // "data":1599090512080,
+ // "message":"Success"
+ // }
+ //
+ return this.safeInteger (response, 'data');
+ }
+
+ async fetchMarkets (params = {}) {
+ const response = await this.publicGetCommonSymbols (params);
+ //
+ // {
+ // "code":"A10000",
+ // "data":[
+ // {
+ // "amountPrecision":8,
+ // "baseCurrency":"BTC",
+ // "minOrderAmount":"0.001",
+ // "minOrderValue":"25",
+ // "pricePrecision":2,
+ // "quoteCurrency":"BRL",
+ // "status":"ONLINE",
+ // "symbol":"BTC_BRL",
+ // "valuePrecision":2
+ // },
+ // ],
+ // "message":"Success"
+ // }
+ //
+ const result = [];
+ const data = this.safeValue (response, 'data', []);
+ for (let i = 0; i < data.length; i++) {
+ const market = data[i];
+ const baseId = this.safeString (market, 'baseCurrency');
+ const quoteId = this.safeString (market, 'quoteCurrency');
+ const id = this.safeString (market, 'symbol');
+ const base = this.safeCurrencyCode (baseId);
+ const quote = this.safeCurrencyCode (quoteId);
+ const symbol = base + '/' + quote;
+ const precision = {
+ 'amount': this.safeInteger (market, 'amountPrecision'),
+ 'price': this.safeInteger (market, 'pricePrecision'),
+ 'cost': this.safeInteger (market, 'valuePrecision'),
+ };
+ const limits = {
+ 'amount': {
+ 'min': this.safeFloat (market, 'minOrderAmount'),
+ 'max': undefined,
+ },
+ 'price': {
+ 'min': undefined,
+ 'max': undefined,
+ },
+ 'cost': {
+ 'min': this.safeFloat (market, 'minOrderValue'),
+ 'max': undefined,
+ },
+ };
+ const status = this.safeString (market, 'status');
+ const active = (status === 'ONLINE');
+ result.push ({
+ 'id': id,
+ 'symbol': symbol,
+ 'base': base,
+ 'quote': quote,
+ 'baseId': baseId,
+ 'quoteId': quoteId,
+ 'precision': precision,
+ 'limits': limits,
+ 'info': market,
+ 'active': active,
+ });
+ }
+ return result;
+ }
+
+ parseTicker (ticker, market = undefined) {
+ //
+ // fetchTicker, fetchTickers
+ //
+ // {
+ // "ask":"61946.1",
+ // "baseVolume24h":"164.41930186",
+ // "bid":"61815",
+ // "high24h":"64930.72",
+ // "lastPrice":"61928.41",
+ // "low24h":"61156.32",
+ // "open24h":"64512.46",
+ // "quoteVolume24h":"10308157.95",
+ // "symbol":"BTC_BRL",
+ // "timestamp":1599091115090
+ // }
+ //
+ const timestamp = this.safeInteger (ticker, 'timestamp');
+ const marketId = this.safeString (ticker, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const open = this.safeFloat (ticker, 'open24h');
+ const last = this.safeFloat (ticker, 'lastPrice');
+ let percentage = undefined;
+ let change = undefined;
+ let average = undefined;
+ if ((last !== undefined) && (open !== undefined)) {
+ change = last - open;
+ percentage = change / open * 100;
+ average = this.sum (last, open) / 2;
+ }
+ const baseVolume = this.safeFloat (ticker, 'baseVolume24h');
+ const quoteVolume = this.safeFloat (ticker, 'quoteVolume24h');
+ const vwap = this.vwap (baseVolume, quoteVolume);
+ return {
+ 'symbol': symbol,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'high': this.safeFloat (ticker, 'high24h'),
+ 'low': this.safeFloat (ticker, 'low24h'),
+ 'bid': this.safeFloat (ticker, 'bid'),
+ 'bidVolume': undefined,
+ 'ask': this.safeFloat (ticker, 'ask'),
+ 'askVolume': undefined,
+ 'vwap': vwap,
+ 'open': open,
+ 'close': last,
+ 'last': last,
+ 'previousClose': undefined,
+ 'change': change,
+ 'percentage': percentage,
+ 'average': average,
+ 'baseVolume': baseVolume,
+ 'quoteVolume': quoteVolume,
+ 'info': ticker,
+ };
+ }
+
+ async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ const response = await this.publicGetMarketTicker (this.extend (request, params));
+ //
+ // {
+ // "code":"A10000",
+ // "data":{
+ // "ask":"61946.1",
+ // "baseVolume24h":"164.41930186",
+ // "bid":"61815",
+ // "high24h":"64930.72",
+ // "lastPrice":"61928.41",
+ // "low24h":"61156.32",
+ // "open24h":"64512.46",
+ // "quoteVolume24h":"10308157.95",
+ // "symbol":"BTC_BRL",
+ // "timestamp":1599091115090
+ // },
+ // "message":"Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseTicker (data, market);
+ }
+
+ async fetchTickers (symbols = undefined, params = {}) {
+ await this.loadMarkets ();
+ const response = await this.publicGetMarketTickers (params);
+ //
+ // {
+ // "code":"A10000",
+ // "data":[
+ // {
+ // "ask":"61879.36",
+ // "baseVolume24h":"164.40955092",
+ // "bid":"61815",
+ // "high24h":"64930.72",
+ // "lastPrice":"61820.04",
+ // "low24h":"61156.32",
+ // "open24h":"64624.19",
+ // "quoteVolume24h":"10307493.92",
+ // "symbol":"BTC_BRL",
+ // "timestamp":1599091291083
+ // },
+ // ],
+ // "message":"Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = {};
+ for (let i = 0; i < data.length; i++) {
+ const ticker = this.parseTicker (data[i]);
+ const symbol = ticker['symbol'];
+ result[symbol] = ticker;
+ }
+ return this.filterByArray (result, 'symbol', symbols);
+ }
+
+ async fetchOrderBook (symbol, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'symbol': this.marketId (symbol),
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 10, max 20
+ }
+ const response = await this.publicGetMarketDepth (this.extend (request, params));
+ //
+ // {
+ // "code":"A10000",
+ // "data":{
+ // "asks":[
+ // ["0.037159","0.3741"],
+ // ["0.037215","0.2706"],
+ // ["0.037222","1.8459"],
+ // ],
+ // "bids":[
+ // ["0.037053","0.3857"],
+ // ["0.036969","0.8101"],
+ // ["0.036953","1.5226"],
+ // ],
+ // "timestamp":1599280414448
+ // },
+ // "message":"Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ const timestamp = this.safeInteger (data, 'timestamp');
+ return this.parseOrderBook (data, timestamp, 'bids', 'asks');
+ }
+
+ parseTrade (trade, market = undefined) {
+ //
+ // public fetchTrades
+ //
+ // {
+ // "amount":"0.0632",
+ // "price":"0.037288",
+ // "side":"BUY",
+ // "timestamp":1599279694576
+ // }
+ //
+ // private fetchOrderTrades
+ //
+ // {
+ // "id": "608717046691139584",
+ // "orderId": "608716957545402368",
+ // "symbol": "BTC_BRL",
+ // "side": "BUY",
+ // "amount": "0.0988",
+ // "price": "45514.76",
+ // "fee": "0.0000988 BTC",
+ // "role": "MAKER",
+ // "timestamp": 1565171053345
+ // }
+ //
+ // private fetchMyTrades
+ //
+ // {
+ // "id": "608717046691139584",
+ // "orderId": "608716957545402368",
+ // "symbol": "BTC_BRL",
+ // "side": "BUY",
+ // "amount": "0.0988",
+ // "price": "45514.76",
+ // "fee": "0.0000988 BTC",
+ // "feeAmount": "0.0000988",
+ // "feeCurrency": "BTC",
+ // "role": "MAKER",
+ // "timestamp": 1565171053345
+ // }
+ //
+ const id = this.safeString (trade, 'id');
+ const orderId = this.safeString (trade, 'orderId');
+ const timestamp = this.safeInteger (trade, 'timestamp');
+ const side = this.safeStringLower (trade, 'side');
+ const price = this.safeFloat (trade, 'price');
+ const amount = this.safeFloat (trade, 'amount');
+ let cost = this.safeFloat (trade, 'volume');
+ if ((cost === undefined) && (amount !== undefined) && (price !== undefined)) {
+ cost = amount * price;
+ }
+ const marketId = this.safeString (trade, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ const takerOrMaker = this.safeStringLower (trade, 'role');
+ const feeString = this.safeString (trade, 'fee');
+ let fee = undefined;
+ if (feeString !== undefined) {
+ const parts = feeString.split (' ');
+ const feeCurrencyId = this.safeString (parts, 1);
+ const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
+ fee = {
+ 'cost': this.safeFloat (parts, 0),
+ 'currency': feeCurrencyCode,
+ };
+ }
+ return {
+ 'id': id,
+ 'order': orderId,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'symbol': symbol,
+ 'type': undefined,
+ 'side': side,
+ 'price': price,
+ 'amount': amount,
+ 'cost': cost,
+ 'takerOrMaker': takerOrMaker,
+ 'fee': fee,
+ 'info': trade,
+ };
+ }
+
+ async fetchTrades (symbol, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ };
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 100
+ }
+ const response = await this.publicGetMarketTrades (this.extend (request, params));
+ //
+ // {
+ // "code":"A10000",
+ // "data":[
+ // {"amount":"0.0632","price":"0.037288","side":"BUY","timestamp":1599279694576},
+ // {"amount":"0.0052","price":"0.03715","side":"SELL","timestamp":1599276606852},
+ // {"amount":"0.0058","price":"0.037188","side":"SELL","timestamp":1599275187812},
+ // ],
+ // "message":"Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const request = {
+ 'symbol': market['id'],
+ 'unit': this.timeframes[timeframe],
+ };
+ const duration = this.parseTimeframe (timeframe);
+ const now = this.seconds ();
+ if (limit === undefined) {
+ limit = 3000; // max
+ }
+ if (since === undefined) {
+ request['from'] = now - limit * duration;
+ request['to'] = now;
+ } else {
+ const startFrom = parseInt (since / 1000);
+ request['from'] = startFrom;
+ request['to'] = this.sum (startFrom, limit * duration);
+ }
+ const response = await this.publicGetMarketKlineHistory (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "amount": 8.25709100,
+ // "closePrice": 62553.20,
+ // "count": 29,
+ // "highPrice": 62592.87,
+ // "lowPrice": 62553.20,
+ // "openPrice": 62554.23,
+ // "score": 1602501480,
+ // "symbol": "BTC_BRL",
+ // "vol": 516784.2504067500
+ // }
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOHLCVs (data, market, timeframe, since, limit);
+ }
+
+ parseOHLCV (ohlcv, market = undefined) {
+ //
+ // {
+ // "amount": 8.25709100,
+ // "closePrice": 62553.20,
+ // "count": 29,
+ // "highPrice": 62592.87,
+ // "lowPrice": 62553.20,
+ // "openPrice": 62554.23,
+ // "score": 1602501480,
+ // "symbol": "BTC_BRL",
+ // "vol": 516784.2504067500
+ // }
+ //
+ const options = this.safeValue (this.options, 'fetchOHLCV', {});
+ const volumeField = this.safeString (options, 'volume', 'amount'); // or vol
+ return [
+ this.safeTimestamp (ohlcv, 'score'),
+ this.safeFloat (ohlcv, 'openPrice'),
+ this.safeFloat (ohlcv, 'highPrice'),
+ this.safeFloat (ohlcv, 'lowPrice'),
+ this.safeFloat (ohlcv, 'closePrice'),
+ this.safeFloat (ohlcv, volumeField),
+ ];
+ }
+
+ async fetchBalance (params = {}) {
+ await this.loadMarkets ();
+ const response = await this.privateGetAccountGetBalance (params);
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "available": "1.23",
+ // "balance": "0.23",
+ // "currency": "BTC",
+ // "hold": "1"
+ // }
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = { 'info': response };
+ for (let i = 0; i < data.length; i++) {
+ const balance = data[i];
+ const currencyId = this.safeString (balance, 'currency');
+ const code = this.safeCurrencyCode (currencyId);
+ const account = this.account ();
+ account['total'] = this.safeFloat (balance, 'available');
+ account['free'] = this.safeFloat (balance, 'balance');
+ account['used'] = this.safeFloat (balance, 'hold');
+ result[code] = account;
+ }
+ return this.parseBalance (result);
+ }
+
+ async createOrder (symbol, type, side, amount, price = undefined, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ const uppercaseType = type.toUpperCase ();
+ const uppercaseSide = side.toUpperCase ();
+ const request = {
+ 'symbol': market['id'],
+ 'type': uppercaseType, // LIMIT, MARKET
+ 'side': uppercaseSide, // or SELL
+ // 'accountId': '...', // subaccount id, optional
+ // 'amount': this.amountToPrecision (symbol, amount),
+ // "price": "1234.5678", // required for LIMIT and STOP orders
+ };
+ if (uppercaseType === 'LIMIT') {
+ request['price'] = this.priceToPrecision (symbol, price);
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ } else if (uppercaseType === 'MARKET') {
+ if (uppercaseSide === 'SELL') {
+ request['amount'] = this.amountToPrecision (symbol, amount);
+ } else if (uppercaseSide === 'BUY') {
+ let value = this.safeFloat (params, 'value');
+ const createMarketBuyOrderRequiresPrice = this.safeValue (this.options, 'createMarketBuyOrderRequiresPrice', true);
+ if (createMarketBuyOrderRequiresPrice) {
+ if (price !== undefined) {
+ if (value === undefined) {
+ value = amount * price;
+ }
+ } else if (value === undefined) {
+ throw new InvalidOrder (this.id + " createOrder() requires the price argument with market buy orders to calculate total order cost (amount to spend), where cost = amount * price. Supply a price argument to createOrder() call if you want the cost to be calculated for you from price and amount, or, alternatively, add .options['createMarketBuyOrderRequiresPrice'] = false and supply the total cost value in the 'amount' argument or in the 'value' extra parameter (the exchange-specific behaviour)");
+ }
+ } else {
+ value = (value === undefined) ? amount : value;
+ }
+ const precision = market['precision']['price'];
+ request['value'] = this.decimalToPrecision (value, TRUNCATE, precision, this.precisionMode);
+ }
+ }
+ const response = await this.privatePostOrdersCreate (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": {
+ // "amount": "0.001",
+ // "averagePrice": null,
+ // "filledAmount": "0",
+ // "filledFee": "0",
+ // "filledValue": "0",
+ // "id": "633679992971251712",
+ // "price": "35000",
+ // "side": "BUY",
+ // "status": "PROCESSING",
+ // "symbol": "BTC_BRL",
+ // "timestamp": 1571122683535,
+ // "type": "LIMIT",
+ // "value": "35"
+ // },
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data, market);
+ }
+
+ async cancelOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const response = await this.privatePostOrdersCancel (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": {
+ // "result": true
+ // },
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data);
+ }
+
+ async fetchOrder (id, symbol = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const response = await this.privateGetOrdersGet (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": {
+ // "id": "608695623247466496",
+ // "symbol": "BTC_BRL",
+ // "type": "MARKET",
+ // "side": "SELL",
+ // "price": null,
+ // "averagePrice": "0",
+ // "amount": "0.123",
+ // "filledAmount": "0",
+ // "value": null,
+ // "filledValue": "0",
+ // "filledFee": "0",
+ // "status": "REJECTED",
+ // "timestamp": 1565165945588
+ // },
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', {});
+ return this.parseOrder (data);
+ }
+
+ async fetchOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'symbol': market['id'],
+ // 'status': 'SUBMITTED,PROCESSING', // SUBMITTED, PROCESSING, PARTIAL_FILLED, CANCELING, FILLED, CANCELED, REJECTED
+ // 'fromId': '...', // order id to begin with
+ // 'toId': '...', // order id to end up with
+ // 'fromTimestamp': since,
+ // 'toTimestamp': this.milliseconds (),
+ // 'limit': limit, // default 100, max 100
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit; // default 100, max 100
+ }
+ if (since !== undefined) {
+ request['fromTimestamp'] = since;
+ }
+ const response = await this.privateGetOrdersList (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "id": "608695678650028032",
+ // "symbol": "BTC_BRL",
+ // "type": "MARKET",
+ // "side": "SELL",
+ // "price": null,
+ // "averagePrice": "0",
+ // "amount": "0.123",
+ // "filledAmount": "0",
+ // "value": null,
+ // "filledValue": "0",
+ // "filledFee": "0",
+ // "status": "REJECTED",
+ // "timestamp": 1565165958796
+ // },
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseOrders (data, market, since, limit);
+ }
+
+ async fetchOpenOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'status': 'SUBMITTED,PROCESSING,PARTIAL_FILLED,CANCELING',
+ };
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchClosedOrders (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'status': 'FILLED,CANCELED,REJECTED',
+ };
+ return await this.fetchOrders (symbol, since, limit, this.extend (request, params));
+ }
+
+ async fetchOrderTrades (id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ 'id': id,
+ };
+ const response = await this.privateGetOrdersFill (this.extend (request, params));
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ }
+ const data = this.safeValue (response, 'data', []);
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "id": "608717046691139584",
+ // "orderId": "608716957545402368",
+ // "symbol": "BTC_BRL",
+ // "side": "BUY",
+ // "amount": "0.0988",
+ // "price": "45514.76",
+ // "fee": "0.0000988 BTC",
+ // "role": "MAKER",
+ // "timestamp": 1565171053345
+ // },
+ // ],
+ // "message": "Success"
+ // }
+ //
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ parseOrderStatus (status) {
+ const statuses = {
+ 'SUBMITTED': 'open',
+ 'PROCESSING': 'open',
+ 'PARTIAL_FILLED': 'open',
+ 'CANCELING': 'open',
+ 'FILLED': 'closed',
+ 'CANCELED': 'canceled',
+ 'REJECTED': 'rejected',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseOrder (order, market = undefined) {
+ //
+ // createOrder, fetchOrders, fetchOrder
+ //
+ // {
+ // "amount": "0.001",
+ // "averagePrice": null,
+ // "filledAmount": "0",
+ // "filledFee": "0",
+ // "filledValue": "0",
+ // "id": "633679992971251712",
+ // "price": "35000",
+ // "side": "BUY",
+ // "status": "PROCESSING",
+ // "symbol": "BTC_BRL",
+ // "timestamp": 1571122683535,
+ // "type": "LIMIT",
+ // "value": "35"
+ // }
+ //
+ // cancelOrder
+ //
+ // {
+ // "result": true
+ // }
+ //
+ const id = this.safeString (order, 'id');
+ const amount = this.safeFloat (order, 'amount');
+ const price = this.safeFloat (order, 'price');
+ const cost = this.safeFloat (order, 'filledValue');
+ const type = this.safeStringLower (order, 'type');
+ const side = this.safeStringLower (order, 'side');
+ const status = this.parseOrderStatus (this.safeString (order, 'status'));
+ const timestamp = this.safeInteger (order, 'timestamp');
+ const average = this.safeFloat (order, 'averagePrice');
+ const filled = this.safeFloat (order, 'filledAmount');
+ let remaining = undefined;
+ if ((amount !== undefined) && (filled !== undefined)) {
+ remaining = Math.max (0, amount - filled);
+ }
+ let fee = undefined;
+ const feeCost = this.safeFloat (order, 'filledFee');
+ if (feeCost !== undefined) {
+ fee = {
+ 'cost': feeCost,
+ 'currency': undefined,
+ };
+ }
+ const marketId = this.safeString (order, 'symbol');
+ const symbol = this.safeSymbol (marketId, market, '_');
+ return {
+ 'id': id,
+ 'clientOrderId': undefined,
+ 'info': order,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'lastTradeTimestamp': undefined,
+ 'symbol': symbol,
+ 'type': type,
+ 'timeInForce': undefined,
+ 'side': side,
+ 'price': price,
+ 'stopPrice': undefined,
+ 'amount': amount,
+ 'cost': cost,
+ 'average': average,
+ 'filled': filled,
+ 'remaining': remaining,
+ 'status': status,
+ 'fee': fee,
+ 'trades': undefined,
+ };
+ }
+
+ async withdraw (code, amount, address, tag = undefined, params = {}) {
+ await this.loadMarkets ();
+ const currency = this.currency (code);
+ const request = {
+ 'code': currency['id'],
+ 'amount': this.currencyToPrecision (code, amount),
+ 'wallet': address,
+ };
+ if (tag !== undefined) {
+ request['tag'] = tag;
+ }
+ const response = await this.privatePostAccountWithdrawCoin (this.extend (request, params));
+ //
+ // {
+ // "code":"A10000",
+ // "data": "DR123",
+ // "message":"Success"
+ // }
+ //
+ return this.parseTransaction (response, currency);
+ }
+
+ async fetchAccounts (params = {}) {
+ const response = await this.privateGetAccountSubs (params);
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "subId": "CA648856083527372800",
+ // "state": "Normal",
+ // "subAccount": "003",
+ // "subIdentify": "003"
+ // }
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ const result = [];
+ for (let i = 0; i < data.length; i++) {
+ const account = data[i];
+ const accountId = this.safeString (account, 'subId');
+ const type = this.safeString (account, 'subAccount');
+ result.push ({
+ 'id': accountId,
+ 'type': type,
+ 'currency': undefined,
+ 'info': account,
+ });
+ }
+ return result;
+ }
+
+ async fetchDeposits (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'type': 'coin_in',
+ };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchWithdrawals (code = undefined, since = undefined, limit = undefined, params = {}) {
+ const request = {
+ 'type': 'coin_out',
+ };
+ return await this.fetchTransactions (code, since, limit, this.extend (request, params));
+ }
+
+ async fetchTransactions (code = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'currency': currency['id'],
+ // 'type': 'coin_in', // 'coin_out'
+ // 'direct': 'asc', // 'desc'
+ // 'size': limit, // default 100
+ // 'start': id, // offset id
+ };
+ let currency = undefined;
+ if (code !== undefined) {
+ currency = this.currency (code);
+ request['currency'] = currency['id'];
+ }
+ if (limit !== undefined) {
+ request['size'] = limit;
+ }
+ const response = await this.privateGetWalletQueryDepositWithdraw (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "id": "DR562339304588709888",
+ // "type": "COIN_IN",
+ // "currency": "XLM",
+ // "chain": "XLM",
+ // "address": "GCUTK7KHPJC3ZQJ3OMWWFHAK2OXIBRD4LNZQRCCOVE7A2XOPP2K5PU5Q",
+ // "addressTag": "1000009",
+ // "amount": 1.0,
+ // "state": "SUCCESS",
+ // "txHash": "39210645748822f8d4ce673c7559aa6622e6e9cdd7073bc0fcae14b1edfda5f4",
+ // "createdAt": 1554113737000,
+ // "updatedAt": 1601371273000
+ // }
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTransactions (data, currency, since, limit);
+ }
+
+ parseTransactionStatus (status) {
+ // Pending the record is wait broadcast to chain
+ // x/M confirming the comfirming state of tx, the M is total confirmings needed
+ // SUCCESS the record is success full
+ // FAIL the record failed
+ const parts = status.split (' ');
+ status = this.safeString (parts, 1, status);
+ const statuses = {
+ 'Pending': 'pending',
+ 'confirming': 'pending',
+ 'SUCCESS': 'ok',
+ 'FAIL': 'failed',
+ };
+ return this.safeString (statuses, status, status);
+ }
+
+ parseTransaction (transaction, currency = undefined) {
+ //
+ // withdraw
+ //
+ // {
+ // "code":"A10000",
+ // "data": "DR123",
+ // "message":"Success"
+ // }
+ //
+ // fetchTransactions
+ //
+ // {
+ // "id": "DR562339304588709888",
+ // "type": "COIN_IN",
+ // "currency": "XLM",
+ // "chain": "XLM",
+ // "address": "GCUTK7KHPJC3ZQJ3OMWWFHAK2OXIBRD4LNZQRCCOVE7A2XOPP2K5PU5Q",
+ // "addressTag": "1000009",
+ // "amount": 1.0,
+ // "state": "SUCCESS",
+ // "txHash": "39210645748822f8d4ce673c7559aa6622e6e9cdd7073bc0fcae14b1edfda5f4",
+ // "createdAt": 1554113737000,
+ // "updatedAt": 1601371273000
+ // }
+ //
+ const id = this.safeString2 (transaction, 'id', 'data');
+ let type = this.safeString (transaction, 'type');
+ if (type === 'COIN_IN') {
+ type = 'deposit';
+ } else if (type === 'COIN_OUT') {
+ type = 'withdraw';
+ }
+ const amount = this.safeFloat (transaction, 'amount');
+ const address = this.safeString (transaction, 'address');
+ const tag = this.safeString (transaction, 'addressTag');
+ const txid = this.safeString (transaction, 'txHash');
+ const timestamp = this.safeInteger (transaction, 'createdAt');
+ const updated = this.safeInteger (transaction, 'updatedAt');
+ const currencyId = this.safeString (transaction, 'currency');
+ const code = this.safeCurrencyCode (currencyId, currency);
+ const status = this.parseTransactionStatus (this.safeString (transaction, 'state'));
+ return {
+ 'info': transaction,
+ 'id': id,
+ 'currency': code,
+ 'amount': amount,
+ 'address': address,
+ 'addressTo': address,
+ 'addressFrom': undefined,
+ 'tag': tag,
+ 'tagTo': tag,
+ 'tagFrom': undefined,
+ 'status': status,
+ 'type': type,
+ 'updated': updated,
+ 'txid': txid,
+ 'timestamp': timestamp,
+ 'datetime': this.iso8601 (timestamp),
+ 'fee': undefined,
+ };
+ }
+
+ async fetchMyTrades (symbol = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ const request = {
+ // 'orderId': id, // Order ID, string
+ // 'symbol': market['id'], // The trading symbol, like BTC_BRL, string
+ // 'fromId': fromId, // Search fill id to begin with, string
+ // 'toId': toId, // Search fill id to end up with, string
+ // 'fromTimestamp': since, // Search order fill time to begin with, in milliseconds, string
+ // 'toTimestamp': this.milliseconds (), // Search order fill time to end up with, in milliseconds, string
+ // 'limit': limit, // The number of fills to return, default 100, max 100, string
+ // 'accountId': subaccountId, // Sub account ID, if not informed, the fills will be return under master account, string
+ };
+ let market = undefined;
+ if (symbol !== undefined) {
+ market = this.market (symbol);
+ request['symbol'] = market['id'];
+ }
+ if (limit !== undefined) {
+ request['limit'] = limit;
+ }
+ if (since !== undefined) {
+ request['fromTimestamp'] = since;
+ }
+ const response = await this.privateGetOrdersFills (this.extend (request, params));
+ //
+ // {
+ // "code": "A10000",
+ // "data": [
+ // {
+ // "id": "608717046691139584",
+ // "orderId": "608716957545402368",
+ // "symbol": "BTC_BRL",
+ // "side": "BUY",
+ // "amount": "0.0988",
+ // "price": "45514.76",
+ // "fee": "0.0000988 BTC",
+ // "feeAmount": "0.0000988",
+ // "feeCurrency": "BTC",
+ // "role": "MAKER",
+ // "timestamp": 1565171053345
+ // },
+ // {
+ // "id": "608717065729085441",
+ // "orderId": "608716957545402368",
+ // "symbol": "BTC_BRL",
+ // "side": "BUY",
+ // "amount": "0.0242",
+ // "price": "45514.76",
+ // "fee": "0.0000242 BTC",
+ // "feeAmount": "0.0000988",
+ // "feeCurrency": "BTC",
+ // "role": "MAKER",
+ // "timestamp": 1565171057882
+ // }
+ // ],
+ // "message": "Success"
+ // }
+ //
+ const data = this.safeValue (response, 'data', []);
+ return this.parseTrades (data, market, since, limit);
+ }
+
+ sign (path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
+ const request = '/' + this.version + '/' + this.implodeParams (path, params);
+ let url = this.urls['api'][api] + request;
+ const query = this.omit (params, this.extractParams (path));
+ if (api === 'public') {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ } else if (api === 'private') {
+ this.checkRequiredCredentials ();
+ const timestamp = this.milliseconds ().toString ();
+ headers = {
+ 'X-Nova-Access-Key': this.apiKey,
+ 'X-Nova-Timestamp': timestamp,
+ };
+ let queryString = undefined;
+ if (method === 'POST') {
+ body = this.json (query);
+ queryString = this.hash (body, 'md5');
+ headers['Content-Type'] = 'application/json';
+ } else {
+ if (Object.keys (query).length) {
+ url += '?' + this.urlencode (query);
+ }
+ queryString = this.urlencode (this.keysort (query));
+ }
+ const auth = method + "\n" + request + "\n" + queryString + "\n" + timestamp; // eslint-disable-line quotes
+ headers['X-Nova-Signature'] = this.hmac (this.encode (auth), this.encode (this.secret));
+ }
+ return { 'url': url, 'method': method, 'body': body, 'headers': headers };
+ }
+
+ handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (response === undefined) {
+ return;
+ }
+ //
+ // {"code":"A10003","data":[],"message":"Authentication failed, Invalid accessKey."}
+ //
+ const errorCode = this.safeString (response, 'code');
+ if (errorCode !== 'A10000') {
+ const message = this.safeString (response, 'message');
+ const feedback = this.id + ' ' + body;
+ this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
+ this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ throw new ExchangeError (feedback); // unknown message
+ }
+ }
+};
diff --git a/TaskServer/node_modules/ccxt/js/oceanex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/oceanex.js
similarity index 95%
rename from TaskServer/node_modules/ccxt/js/oceanex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/oceanex.js
index 4cea6ef6b..b77c3dde7 100644
--- a/TaskServer/node_modules/ccxt/js/oceanex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/oceanex.js
@@ -229,11 +229,11 @@ module.exports = class oceanex extends Exchange {
for (let i = 0; i < data.length; i++) {
const ticker = data[i];
const marketId = this.safeString (ticker, 'market');
- const market = this.markets_by_id[marketId];
+ const market = this.safeMarket (marketId);
const symbol = market['symbol'];
result[symbol] = this.parseTicker (ticker, market);
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
parseTicker (data, market = undefined) {
@@ -351,8 +351,7 @@ module.exports = class oceanex extends Exchange {
for (let i = 0; i < data.length; i++) {
const orderbook = data[i];
const marketId = this.safeString (orderbook, 'market');
- const market = this.markets_by_id[marketId];
- const symbol = market['symbol'];
+ const symbol = this.safeSymbol (marketId);
const timestamp = this.safeTimestamp (orderbook, 'timestamp');
result[symbol] = this.parseOrderBook (orderbook, timestamp);
}
@@ -380,21 +379,8 @@ module.exports = class oceanex extends Exchange {
} else if (side === 'ask') {
side = 'sell';
}
- let symbol = undefined;
const marketId = this.safeValue (trade, 'market');
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const symbol = this.safeSymbol (marketId, market);
let timestamp = this.safeTimestamp (trade, 'created_on');
if (timestamp === undefined) {
timestamp = this.parse8601 (this.safeString (trade, 'created_at'));
@@ -433,10 +419,7 @@ module.exports = class oceanex extends Exchange {
const maker = this.safeValue (group, 'ask_fee', {});
const taker = this.safeValue (group, 'bid_fee', {});
const marketId = this.safeString (group, 'market');
- let symbol = marketId;
- if (marketId in this.markets_by_id) {
- symbol = this.markets_by_id[marketId]['symbol'];
- }
+ const symbol = this.safeSymbol (marketId);
result[symbol] = {
'info': group,
'symbol': symbol,
@@ -574,21 +557,8 @@ module.exports = class oceanex extends Exchange {
// }
//
const status = this.parseOrderStatus (this.safeValue (order, 'state'));
- const marketId = this.safeValue2 (order, 'market', 'market_id');
- let symbol = undefined;
- if (marketId !== undefined) {
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- symbol = market['symbol'];
- } else {
- symbol = marketId;
- }
- }
- if (symbol === undefined) {
- if (market !== undefined) {
- symbol = market['symbol'];
- }
- }
+ const marketId = this.safeString2 (order, 'market', 'market_id');
+ const symbol = this.safeSymbol (marketId);
let timestamp = this.safeTimestamp (order, 'created_on');
if (timestamp === undefined) {
timestamp = this.parse8601 (this.safeString (order, 'created_at'));
@@ -602,8 +572,10 @@ module.exports = class oceanex extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': this.safeValue (order, 'ord_type'),
+ 'timeInForce': undefined,
'side': this.safeValue (order, 'side'),
'price': this.safeFloat (order, 'price'),
+ 'stopPrice': undefined,
'average': this.safeFloat (order, 'avg_price'),
'amount': this.safeFloat (order, 'volume'),
'remaining': this.safeFloat (order, 'remaining_volume'),
diff --git a/TaskServer/node_modules/ccxt/js/okcoin.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/okcoin.js
similarity index 94%
rename from TaskServer/node_modules/ccxt/js/okcoin.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/okcoin.js
index 59c0c3cb2..73a624f67 100644
--- a/TaskServer/node_modules/ccxt/js/okcoin.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/okcoin.js
@@ -15,7 +15,7 @@ module.exports = class okcoin extends okex {
'hostname': 'okcoin.com',
'pro': true,
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27766791-89ffb502-5ee5-11e7-8a5b-c5950b68ac65.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87295551-102fbf00-c50e-11ea-90a9-462eebba5829.jpg',
'www': 'https://www.okcoin.com',
'doc': 'https://www.okcoin.com/docs/en/',
'fees': 'https://www.okcoin.com/coin-fees',
diff --git a/TaskServer/node_modules/ccxt/js/okex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/okex.js
similarity index 84%
rename from TaskServer/node_modules/ccxt/js/okex.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/okex.js
index c05baf41b..a1d6e3c48 100644
--- a/TaskServer/node_modules/ccxt/js/okex.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/okex.js
@@ -18,24 +18,31 @@ module.exports = class okex extends Exchange {
'rateLimit': 1000, // up to 3000 requests per 5 minutes ≈ 600 requests per minute ≈ 10 requests per second ≈ 100 ms
'pro': true,
'has': {
+ 'cancelOrder': true,
'CORS': false,
- 'fetchOHLCV': true,
- 'fetchOrder': true,
- 'fetchOrders': false,
- 'fetchOpenOrders': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
'fetchClosedOrders': true,
'fetchCurrencies': false, // see below
- 'fetchDeposits': true,
- 'fetchWithdrawals': true,
- 'fetchTime': true,
- 'fetchTransactions': false,
- 'fetchMyTrades': true,
'fetchDepositAddress': true,
- 'fetchOrderTrades': true,
- 'fetchTickers': true,
+ 'fetchDeposits': true,
'fetchLedger': true,
- 'withdraw': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': false,
+ 'fetchOrderTrades': true,
+ 'fetchTime': true,
+ 'fetchTicker': true,
+ 'fetchTickers': true,
+ 'fetchTrades': true,
+ 'fetchTransactions': false,
+ 'fetchWithdrawals': true,
'futures': true,
+ 'withdraw': true,
},
'timeframes': {
'1m': '60',
@@ -50,6 +57,10 @@ module.exports = class okex extends Exchange {
'12h': '43200',
'1d': '86400',
'1w': '604800',
+ '1M': '2678400',
+ '3M': '8035200',
+ '6M': '16070400',
+ '1y': '31536000',
},
'hostname': 'okex.com',
'urls': {
@@ -110,6 +121,7 @@ module.exports = class okex extends Exchange {
'instruments/{instrument_id}/ticker',
'instruments/{instrument_id}/trades',
'instruments/{instrument_id}/candles',
+ 'instruments/{instrument_id}/history/candles',
],
'post': [
'order_algo',
@@ -174,6 +186,7 @@ module.exports = class okex extends Exchange {
'instruments/{instrument_id}/ticker',
'instruments/{instrument_id}/trades',
'instruments/{instrument_id}/candles',
+ 'instruments/{instrument_id}/history/candles',
'instruments/{instrument_id}/index',
'rate',
'instruments/{instrument_id}/estimated_price',
@@ -218,6 +231,7 @@ module.exports = class okex extends Exchange {
'instruments/{instrument_id}/ticker',
'instruments/{instrument_id}/trades',
'instruments/{instrument_id}/candles',
+ 'instruments/{instrument_id}/history/candles',
'instruments/{instrument_id}/index',
'rate',
'instruments/{instrument_id}/open_interest',
@@ -241,6 +255,7 @@ module.exports = class okex extends Exchange {
'option': {
'get': [
'accounts',
+ 'position',
'{underlying}/position',
'accounts/{underlying}',
'orders/{underlying}',
@@ -304,11 +319,15 @@ module.exports = class okex extends Exchange {
// 401 Unauthorized — Invalid API Key
// 403 Forbidden — You do not have access to the requested resource
// 404 Not Found
+ // 429 Client Error: Too Many Requests for url
// 500 Internal Server Error — We had a problem with our server
'exact': {
'1': ExchangeError, // { "code": 1, "message": "System error" }
// undocumented
'failure to get a peer from the ring-balancer': ExchangeNotAvailable, // { "message": "failure to get a peer from the ring-balancer" }
+ 'Server is busy, please try again.': ExchangeNotAvailable, // { "message": "Server is busy, please try again." }
+ 'An unexpected error occurred': ExchangeError, // { "message": "An unexpected error occurred" }
+ 'System error': ExchangeError, // {"error_message":"System error","message":"System error"}
'4010': PermissionDenied, // { "code": 4010, "message": "For the security of your funds, withdrawals are not permitted within 24 hours after changing fund password / mobile number / Google Authenticator settings " }
// common
// '0': ExchangeError, // 200 successful,when the order placement / cancellation / operation is successful
@@ -344,7 +363,7 @@ module.exports = class okex extends Exchange {
'30027': AuthenticationError, // { "code": 30027, "message": "login failure" }
'30028': PermissionDenied, // { "code": 30028, "message": "unauthorized execution" }
'30029': AccountSuspended, // { "code": 30029, "message": "account suspended" }
- '30030': ExchangeError, // { "code": 30030, "message": "endpoint request failed. Please try again" }
+ '30030': ExchangeNotAvailable, // { "code": 30030, "message": "endpoint request failed. Please try again" }
'30031': BadRequest, // { "code": 30031, "message": "token does not exist" }
'30032': BadSymbol, // { "code": 30032, "message": "pair does not exist" }
'30033': BadRequest, // { "code": 30033, "message": "exchange domain does not exist" }
@@ -354,6 +373,7 @@ module.exports = class okex extends Exchange {
'30037': ExchangeNotAvailable, // { "code": 30037, "message": "endpoint is offline or unavailable" }
// '30038': AuthenticationError, // { "code": 30038, "message": "user does not exist" }
'30038': OnMaintenance, // {"client_oid":"","code":"30038","error_code":"30038","error_message":"Matching engine is being upgraded. Please try in about 1 minute.","message":"Matching engine is being upgraded. Please try in about 1 minute.","order_id":"-1","result":false}
+ '30044': RequestTimeout, // { "code":30044, "message":"Endpoint request timeout" }
// futures
'32001': AccountSuspended, // { "code": 32001, "message": "futures account suspended" }
'32002': PermissionDenied, // { "code": 32002, "message": "futures account does not exist" }
@@ -434,7 +454,7 @@ module.exports = class okex extends Exchange {
'33005': ExchangeError, // { "code": 33005, "message": "repayment amount must exceed 0" }
'33006': ExchangeError, // { "code": 33006, "message": "loan order not found" }
'33007': ExchangeError, // { "code": 33007, "message": "status not found" }
- '33008': ExchangeError, // { "code": 33008, "message": "loan amount cannot exceed the maximum limit" }
+ '33008': InsufficientFunds, // { "code": 33008, "message": "loan amount cannot exceed the maximum limit" }
'33009': ExchangeError, // { "code": 33009, "message": "user ID is blank" }
'33010': ExchangeError, // { "code": 33010, "message": "you cannot cancel an order during session 2 of call auction" }
'33011': ExchangeError, // { "code": 33011, "message": "no new market data" }
@@ -480,6 +500,7 @@ module.exports = class okex extends Exchange {
'33063': ExchangeError, // Leverage multiple is too low, there is insufficient margin in the account, please readjust the leverage ratio
'33064': ExchangeError, // The setting of the leverage ratio cannot be less than 2, please readjust the leverage ratio
'33065': ExchangeError, // Leverage ratio exceeds maximum leverage ratio, please readjust leverage ratio
+ '33085': InvalidOrder, // The value of the position and buying order has reached the position limit, and no further buying is allowed.
// account
'21009': ExchangeError, // Funds cannot be transferred out within 30 minutes after swap settlement(Funds cannot be transferred out within 30 minutes after swap settlement)
'34001': PermissionDenied, // { "code": 34001, "message": "withdrawal suspended" }
@@ -525,10 +546,10 @@ module.exports = class okex extends Exchange {
'35019': InvalidOrder, // { "code": 35019, "message": "Order size too large" }
'35020': InvalidOrder, // { "code": 35020, "message": "Order price too high" }
'35021': InvalidOrder, // { "code": 35021, "message": "Order size exceeded current tier limit" }
- '35022': ExchangeError, // { "code": 35022, "message": "Contract status error" }
- '35024': ExchangeError, // { "code": 35024, "message": "Contract not initialized" }
+ '35022': BadRequest, // { "code": 35022, "message": "Contract status error" }
+ '35024': BadRequest, // { "code": 35024, "message": "Contract not initialized" }
'35025': InsufficientFunds, // { "code": 35025, "message": "No account balance" }
- '35026': ExchangeError, // { "code": 35026, "message": "Contract settings not initialized" }
+ '35026': BadRequest, // { "code": 35026, "message": "Contract settings not initialized" }
'35029': OrderNotFound, // { "code": 35029, "message": "Order does not exist" }
'35030': InvalidOrder, // { "code": 35030, "message": "Order size too large" }
'35031': InvalidOrder, // { "code": 35031, "message": "Cancel order size too large" }
@@ -635,6 +656,9 @@ module.exports = class okex extends Exchange {
},
'precisionMode': TICK_SIZE,
'options': {
+ 'fetchOHLCV': {
+ 'type': 'Candles', // Candles or HistoryCandles
+ },
'createMarketBuyOrderRequiresPrice': true,
'fetchMarkets': [ 'spot', 'futures', 'swap', 'option' ],
'defaultType': 'spot', // 'account', 'spot', 'margin', 'futures', 'swap', 'option'
@@ -649,6 +673,7 @@ module.exports = class okex extends Exchange {
'commonCurrencies': {
// OKEX refers to ERC20 version of Aeternity (AEToken)
'AE': 'AET', // https://github.com/ccxt/ccxt/issues/4981
+ 'BOX': 'DefiBox',
'HOT': 'Hydro Protocol',
'HSR': 'HC',
'MAG': 'Maggie',
@@ -955,7 +980,7 @@ module.exports = class okex extends Exchange {
const name = this.safeString (currency, 'name');
const canDeposit = this.safeInteger (currency, 'can_deposit');
const canWithdraw = this.safeInteger (currency, 'can_withdraw');
- const active = canDeposit && canWithdraw;
+ const active = (canDeposit && canWithdraw) ? true : false;
result[code] = {
'id': id,
'code': code,
@@ -1107,7 +1132,7 @@ module.exports = class okex extends Exchange {
const symbol = ticker['symbol'];
result[symbol] = ticker;
}
- return result;
+ return this.filterByArray (result, 'symbol', symbols);
}
async fetchTickers (symbols = undefined, params = {}) {
@@ -1294,7 +1319,7 @@ module.exports = class okex extends Exchange {
return this.parseTrades (response, market, since, limit);
}
- parseOHLCV (ohlcv, market = undefined, timeframe = '1m', since = undefined, limit = undefined) {
+ parseOHLCV (ohlcv, market = undefined) {
//
// spot markets
//
@@ -1322,19 +1347,19 @@ module.exports = class okex extends Exchange {
if (Array.isArray (ohlcv)) {
const numElements = ohlcv.length;
const volumeIndex = (numElements > 6) ? 6 : 5;
- let timestamp = ohlcv[0];
+ let timestamp = this.safeValue (ohlcv, 0);
if (typeof timestamp === 'string') {
timestamp = this.parse8601 (timestamp);
}
return [
timestamp, // timestamp
- parseFloat (ohlcv[1]), // Open
- parseFloat (ohlcv[2]), // High
- parseFloat (ohlcv[3]), // Low
- parseFloat (ohlcv[4]), // Close
- // parseFloat (ohlcv[5]), // Quote Volume
- // parseFloat (ohlcv[6]), // Base Volume
- parseFloat (ohlcv[volumeIndex]), // Volume, okex will return base volume in the 7th element for future markets
+ this.safeFloat (ohlcv, 1), // Open
+ this.safeFloat (ohlcv, 2), // High
+ this.safeFloat (ohlcv, 3), // Low
+ this.safeFloat (ohlcv, 4), // Close
+ // this.safeFloat (ohlcv, 5), // Quote Volume
+ // this.safeFloat (ohlcv, 6), // Base Volume
+ this.safeFloat (ohlcv, volumeIndex), // Volume, okex will return base volume in the 7th element for future markets
];
} else {
return [
@@ -1351,59 +1376,92 @@ module.exports = class okex extends Exchange {
async fetchOHLCV (symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const market = this.market (symbol);
- const method = market['type'] + 'GetInstrumentsInstrumentIdCandles';
+ const duration = this.parseTimeframe (timeframe);
const request = {
'instrument_id': market['id'],
'granularity': this.timeframes[timeframe],
};
- const duration = this.parseTimeframe (timeframe);
- if (since !== undefined) {
- if (limit !== undefined) {
- request['end'] = this.iso8601 (this.sum (since, limit * duration * 1000));
+ const options = this.safeValue (this.options, 'fetchOHLCV', {});
+ const defaultType = this.safeString (options, 'type', 'Candles'); // Candles or HistoryCandles
+ const type = this.safeString (params, 'type', defaultType);
+ params = this.omit (params, 'type');
+ const method = market['type'] + 'GetInstrumentsInstrumentId' + type;
+ if (type === 'Candles') {
+ if (since !== undefined) {
+ if (limit !== undefined) {
+ request['end'] = this.iso8601 (this.sum (since, limit * duration * 1000));
+ }
+ request['start'] = this.iso8601 (since);
+ } else {
+ if (limit !== undefined) {
+ const now = this.milliseconds ();
+ request['start'] = this.iso8601 (now - limit * duration * 1000);
+ request['end'] = this.iso8601 (now);
+ }
}
- request['start'] = this.iso8601 (since);
- } else {
- const now = this.milliseconds ();
- if (limit !== undefined) {
- request['start'] = this.iso8601 (now - limit * duration * 1000);
- request['end'] = this.iso8601 (now);
+ } else if (type === 'HistoryCandles') {
+ if (market['option']) {
+ throw new NotSupported (this.id + ' fetchOHLCV does not have ' + type + ' for ' + market['type'] + ' markets');
+ }
+ if (since !== undefined) {
+ if (limit === undefined) {
+ limit = 300; // default
+ }
+ request['start'] = this.iso8601 (this.sum (since, limit * duration * 1000));
+ request['end'] = this.iso8601 (since);
+ } else {
+ if (limit !== undefined) {
+ const now = this.milliseconds ();
+ request['end'] = this.iso8601 (now - limit * duration * 1000);
+ request['start'] = this.iso8601 (now);
+ }
}
}
const response = await this[method] (this.extend (request, params));
//
// spot markets
//
- // [ { close: "0.02683401",
- // high: "0.02683401",
- // low: "0.02683401",
- // open: "0.02683401",
- // time: "2018-12-17T23:47:00.000Z",
- // volume: "0" },
- // ...
- // { close: "0.02684545",
- // high: "0.02685084",
- // low: "0.02683312",
- // open: "0.02683894",
- // time: "2018-12-17T20:28:00.000Z",
- // volume: "101.457222" } ]
+ // [
+ // {
+ // close: "0.02683401",
+ // high: "0.02683401",
+ // low: "0.02683401",
+ // open: "0.02683401",
+ // time: "2018-12-17T23:47:00.000Z",
+ // volume: "0"
+ // },
+ // {
+ // close: "0.02684545",
+ // high: "0.02685084",
+ // low: "0.02683312",
+ // open: "0.02683894",
+ // time: "2018-12-17T20:28:00.000Z",
+ // volume: "101.457222"
+ // }
+ // ]
//
// futures
//
- // [ [ 1545090660000,
- // 0.3171,
- // 0.3174,
- // 0.3171,
- // 0.3173,
- // 1648,
- // 51930.38579450868 ],
- // ...
- // [ 1545072720000,
- // 0.3159,
- // 0.3161,
- // 0.3144,
- // 0.3149,
- // 22886,
- // 725179.26172331 ] ]
+ // [
+ // [
+ // 1545090660000,
+ // 0.3171,
+ // 0.3174,
+ // 0.3171,
+ // 0.3173,
+ // 1648,
+ // 51930.38579450868
+ // ],
+ // [
+ // 1545072720000,
+ // 0.3159,
+ // 0.3161,
+ // 0.3144,
+ // 0.3149,
+ // 22886,
+ // 725179.26172331
+ // ]
+ // ]
//
return this.parseOHLCVs (response, market, timeframe, since, limit);
}
@@ -1583,9 +1641,29 @@ module.exports = class okex extends Exchange {
const code = this.safeCurrencyCode (id);
const balance = this.safeValue (info, id, {});
const account = this.account ();
+ const totalAvailBalance = this.safeFloat (balance, 'total_avail_balance');
+ if (this.safeString (balance, 'margin_mode') === 'fixed') {
+ const contracts = this.safeValue (balance, 'contracts', []);
+ let free = totalAvailBalance;
+ for (let i = 0; i < contracts.length; i++) {
+ const contract = contracts[i];
+ const fixedBalance = this.safeFloat (contract, 'fixed_balance');
+ const realizedPnl = this.safeFloat (contract, 'realized_pnl');
+ const marginFrozen = this.safeFloat (contract, 'margin_frozen');
+ const marginForUnfilled = this.safeFloat (contract, 'margin_for_unfilled');
+ const margin = this.sum (fixedBalance, realizedPnl) - marginFrozen - marginForUnfilled;
+ free = this.sum (free, margin);
+ }
+ account['free'] = free;
+ } else {
+ const realizedPnl = this.safeFloat (balance, 'realized_pnl');
+ const unrealizedPnl = this.safeFloat (balance, 'unrealized_pnl');
+ const marginFrozen = this.safeFloat (balance, 'margin_frozen');
+ const marginForUnfilled = this.safeFloat (balance, 'margin_for_unfilled');
+ account['free'] = this.sum (totalAvailBalance, realizedPnl, unrealizedPnl) - marginFrozen - marginForUnfilled;
+ }
// it may be incorrect to use total, free and used for swap accounts
account['total'] = this.safeFloat (balance, 'equity');
- account['free'] = this.safeFloat (balance, 'total_avail_balance');
result[code] = account;
}
return this.parseBalance (result);
@@ -1788,17 +1866,29 @@ module.exports = class okex extends Exchange {
let request = {
'instrument_id': market['id'],
// 'client_oid': 'abcdef1234567890', // [a-z0-9]{1,32}
- // 'order_type': '0', // 0: Normal limit order (Unfilled and 0 represent normal limit order) 1: Post only 2: Fill Or Kill 3: Immediatel Or Cancel
+ // 'order_type': '0', // 0 = Normal limit order, 1 = Post only, 2 = Fill Or Kill, 3 = Immediatel Or Cancel, 4 = Market for futures only
};
+ const clientOrderId = this.safeString2 (params, 'client_oid', 'clientOrderId');
+ if (clientOrderId !== undefined) {
+ request['client_oid'] = clientOrderId;
+ params = this.omit (params, [ 'client_oid', 'clientOrderId' ]);
+ }
let method = undefined;
if (market['futures'] || market['swap']) {
const size = market['futures'] ? this.numberToString (amount) : this.amountToPrecision (symbol, amount);
request = this.extend (request, {
'type': type, // 1:open long 2:open short 3:close long 4:close short for futures
'size': size,
- 'price': this.priceToPrecision (symbol, price),
// 'match_price': '0', // Order at best counter party price? (0:no 1:yes). The default is 0. If it is set as 1, the price parameter will be ignored. When posting orders at best bid price, order_type can only be 0 (regular order).
});
+ const orderType = this.safeString (params, 'order_type');
+ // order_type === '4' means a market order
+ const isMarketOrder = (type === 'market') || (orderType === '4');
+ if (isMarketOrder) {
+ request['order_type'] = '4';
+ } else {
+ request['price'] = this.priceToPrecision (symbol, price);
+ }
if (market['futures']) {
request['leverage'] = '10'; // or '20'
}
@@ -1847,7 +1937,11 @@ module.exports = class okex extends Exchange {
// "result":true
// }
//
- return this.parseOrder (response, market);
+ const order = this.parseOrder (response, market);
+ return this.extend (order, {
+ 'type': type,
+ 'side': side,
+ });
}
async cancelOrder (id, symbol = undefined, params = {}) {
@@ -1856,7 +1950,16 @@ module.exports = class okex extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
- const type = market['type'];
+ let type = undefined;
+ if (market['futures'] || market['swap']) {
+ type = market['type'];
+ } else {
+ const defaultType = this.safeString2 (this.options, 'cancelOrder', 'defaultType', market['type']);
+ type = this.safeString (params, 'type', defaultType);
+ }
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " cancelOrder requires a type parameter (one of 'spot', 'margin', 'futures', 'swap').");
+ }
let method = type + 'PostCancelOrder';
const request = {
'instrument_id': market['id'],
@@ -1866,15 +1969,15 @@ module.exports = class okex extends Exchange {
} else {
method += 's';
}
- const clientOid = this.safeString (params, 'client_oid');
- if (clientOid !== undefined) {
+ const clientOrderId = this.safeString2 (params, 'client_oid', 'clientOrderId');
+ if (clientOrderId !== undefined) {
method += 'ClientOid';
- request['client_oid'] = clientOid;
+ request['client_oid'] = clientOrderId;
} else {
method += 'OrderId';
request['order_id'] = id;
}
- const query = this.omit (params, 'type');
+ const query = this.omit (params, [ 'type', 'client_oid', 'clientOrderId' ]);
const response = await this[method] (this.extend (request, query));
const result = ('result' in response) ? response : this.safeValue (response, market['id'], {});
//
@@ -1996,17 +2099,10 @@ module.exports = class okex extends Exchange {
const id = this.safeString (order, 'order_id');
const timestamp = this.parse8601 (this.safeString (order, 'timestamp'));
let side = this.safeString (order, 'side');
- let type = this.safeString (order, 'type');
+ const type = this.safeString (order, 'type');
if ((side !== 'buy') && (side !== 'sell')) {
side = this.parseOrderSide (type);
}
- if ((type !== 'limit') && (type !== 'market')) {
- if ('pnl' in order) {
- type = 'futures';
- } else {
- type = 'swap';
- }
- }
let symbol = undefined;
const marketId = this.safeString (order, 'instrument_id');
if (marketId in this.markets_by_id) {
@@ -2054,7 +2150,11 @@ module.exports = class okex extends Exchange {
'currency': feeCurrency,
};
}
- const clientOrderId = this.safeString (order, 'client_oid');
+ let clientOrderId = this.safeString (order, 'client_oid');
+ if ((clientOrderId !== undefined) && (clientOrderId.length < 1)) {
+ clientOrderId = undefined; // fix empty clientOrderId string
+ }
+ const stopPrice = this.safeFloat (order, 'trigger_price');
return {
'info': order,
'id': id,
@@ -2064,8 +2164,10 @@ module.exports = class okex extends Exchange {
'lastTradeTimestamp': undefined,
'symbol': symbol,
'type': type,
+ 'timeInForce': undefined,
'side': side,
'price': price,
+ 'stopPrice': stopPrice,
'average': average,
'cost': cost,
'amount': amount,
@@ -2158,7 +2260,16 @@ module.exports = class okex extends Exchange {
}
await this.loadMarkets ();
const market = this.market (symbol);
- const type = market['type'];
+ let type = undefined;
+ if (market['futures'] || market['swap']) {
+ type = market['type'];
+ } else {
+ const defaultType = this.safeString2 (this.options, 'fetchOrder', 'defaultType', market['type']);
+ type = this.safeString (params, 'type', defaultType);
+ }
+ if (type === undefined) {
+ throw new ArgumentsRequired (this.id + " fetchOrder requires a type parameter (one of 'spot', 'margin', 'futures', 'swap').");
+ }
const request = {
'instrument_id': market['id'],
// '-2': failed,
@@ -2239,7 +2350,7 @@ module.exports = class okex extends Exchange {
// }
//
let orders = undefined;
- if (market['type'] === 'swap' || market['type'] === 'futures') {
+ if (market['swap'] || market['futures']) {
orders = this.safeValue (response, 'order_info', []);
} else {
orders = response;
@@ -2395,7 +2506,7 @@ module.exports = class okex extends Exchange {
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
- request['code'] = currency['code'];
+ request['currency'] = currency['id'];
method += 'Currency';
}
const response = await this[method] (this.extend (request, params));
@@ -2409,7 +2520,7 @@ module.exports = class okex extends Exchange {
let currency = undefined;
if (code !== undefined) {
currency = this.currency (code);
- request['code'] = currency['code'];
+ request['currency'] = currency['id'];
method += 'Currency';
}
const response = await this[method] (this.extend (request, params));
@@ -2442,7 +2553,7 @@ module.exports = class okex extends Exchange {
//
const statuses = {
'-3': 'pending',
- '-2': 'pending',
+ '-2': 'canceled',
'-1': 'failed',
'0': 'pending',
'1': 'pending',
@@ -2482,12 +2593,14 @@ module.exports = class okex extends Exchange {
// fetchDeposits
//
// {
- // amount: "0.47847546",
- // txid: "1723573_3_0_0_WALLET",
- // currency: "BTC",
- // to: "",
- // timestamp: "2018-08-16T03:41:10.000Z",
- // status: "2"
+ // "amount": "4.19511659",
+ // "txid": "14c9a8c925647cdb7e5b2937ea9aefe2b29b2c273150ad3f44b3b8a4635ed437",
+ // "currency": "XMR",
+ // "from": "",
+ // "to": "48PjH3ksv1fiXniKvKvyH5UtFs5WhfS2Vf7U3TwzdRJtCc7HJWvCQe56dRahyhQyTAViXZ8Nzk4gQg6o4BJBMUoxNy8y8g7",
+ // "deposit_id": 11571659, <-- we can use this
+ // "timestamp": "2019-10-01T14:54:19.000Z",
+ // "status": "2"
// }
//
let type = undefined;
@@ -2502,7 +2615,7 @@ module.exports = class okex extends Exchange {
address = addressTo;
} else {
// the payment_id will appear on new deposits but appears to be removed from the response after 2 months
- id = this.safeString (transaction, 'payment_id');
+ id = this.safeString2 (transaction, 'payment_id', 'deposit_id');
type = 'deposit';
address = addressTo;
}
@@ -2553,49 +2666,74 @@ module.exports = class okex extends Exchange {
parseMyTrade (pair, market = undefined) {
// check that trading symbols match in both entries
- const first = pair[0];
- const second = pair[1];
- const firstMarketId = this.safeString (first, 'instrument_id');
- const secondMarketId = this.safeString (second, 'instrument_id');
+ const userTrade = this.safeValue (pair, 1);
+ const otherTrade = this.safeValue (pair, 0);
+ const firstMarketId = this.safeString (otherTrade, 'instrument_id');
+ const secondMarketId = this.safeString (userTrade, 'instrument_id');
if (firstMarketId !== secondMarketId) {
throw new NotSupported (this.id + ' parseMyTrade() received unrecognized response format, differing instrument_ids in one fill, the exchange API might have changed, paste your verbose output: https://github.com/ccxt/ccxt/wiki/FAQ#what-is-required-to-get-help');
}
const marketId = firstMarketId;
- // determine the base and quote
- let quoteId = undefined;
- let symbol = undefined;
- if (marketId in this.markets_by_id) {
- market = this.markets_by_id[marketId];
- quoteId = market['quoteId'];
- symbol = market['symbol'];
- } else {
- const parts = marketId.split ('-');
- quoteId = this.safeString (parts, 1);
- symbol = marketId;
- }
- const id = this.safeString (first, 'trade_id');
- const price = this.safeFloat (first, 'price');
- // determine buy/sell side and amounts
- // get the side from either the first trade or the second trade
- let feeCost = this.safeFloat (first, 'fee');
- const index = (feeCost !== 0) ? 0 : 1;
- const userTrade = this.safeValue (pair, index);
- const otherTrade = this.safeValue (pair, 1 - index);
- const receivedCurrencyId = this.safeString (userTrade, 'currency');
+ market = this.safeMarket (marketId, market);
+ const symbol = market['symbol'];
+ const quoteId = market['quoteId'];
let side = undefined;
let amount = undefined;
let cost = undefined;
+ const receivedCurrencyId = this.safeString (userTrade, 'currency');
+ let feeCurrencyId = undefined;
if (receivedCurrencyId === quoteId) {
- side = 'sell';
+ side = this.safeString (otherTrade, 'side');
amount = this.safeFloat (otherTrade, 'size');
cost = this.safeFloat (userTrade, 'size');
+ feeCurrencyId = this.safeString (otherTrade, 'currency');
} else {
- side = 'buy';
+ side = this.safeString (userTrade, 'side');
amount = this.safeFloat (userTrade, 'size');
cost = this.safeFloat (otherTrade, 'size');
+ feeCurrencyId = this.safeString (userTrade, 'currency');
+ }
+ const id = this.safeString (userTrade, 'trade_id');
+ const price = this.safeFloat (userTrade, 'price');
+ const feeCostFirst = this.safeFloat (otherTrade, 'fee');
+ const feeCostSecond = this.safeFloat (userTrade, 'fee');
+ const feeCurrencyCodeFirst = this.safeCurrencyCode (this.safeString (otherTrade, 'currency'));
+ const feeCurrencyCodeSecond = this.safeCurrencyCode (this.safeString (userTrade, 'currency'));
+ let fee = undefined;
+ let fees = undefined;
+ // fee is either a positive number (invitation rebate)
+ // or a negative number (transaction fee deduction)
+ // therefore we need to invert the fee
+ // more about it https://github.com/ccxt/ccxt/issues/5909
+ if ((feeCostFirst !== undefined) && (feeCostFirst !== 0)) {
+ if ((feeCostSecond !== undefined) && (feeCostSecond !== 0)) {
+ fees = [
+ {
+ 'cost': -feeCostFirst,
+ 'currency': feeCurrencyCodeFirst,
+ },
+ {
+ 'cost': -feeCostSecond,
+ 'currency': feeCurrencyCodeSecond,
+ },
+ ];
+ } else {
+ fee = {
+ 'cost': -feeCostFirst,
+ 'currency': feeCurrencyCodeFirst,
+ };
+ }
+ } else if ((feeCostSecond !== undefined) && (feeCostSecond !== 0)) {
+ fee = {
+ 'cost': -feeCostSecond,
+ 'currency': feeCurrencyCodeSecond,
+ };
+ } else {
+ fee = {
+ 'cost': 0,
+ 'currency': this.safeCurrencyCode (feeCurrencyId),
+ };
}
- feeCost = (feeCost !== 0) ? feeCost : this.safeFloat (second, 'fee');
- const trade = this.safeValue (pair, index);
//
// simplified structures to show the underlying semantics
//
@@ -2629,28 +2767,15 @@ module.exports = class okex extends Exchange {
// "size":"31.03998952", // ←-- cost
// }
//
- const timestamp = this.parse8601 (this.safeString2 (trade, 'timestamp', 'created_at'));
- let takerOrMaker = this.safeString2 (trade, 'exec_type', 'liquidity');
+ const timestamp = this.parse8601 (this.safeString2 (userTrade, 'timestamp', 'created_at'));
+ let takerOrMaker = this.safeString2 (userTrade, 'exec_type', 'liquidity');
if (takerOrMaker === 'M') {
takerOrMaker = 'maker';
} else if (takerOrMaker === 'T') {
takerOrMaker = 'taker';
}
- let fee = undefined;
- if (feeCost !== undefined) {
- const feeCurrencyId = this.safeString (userTrade, 'currency');
- const feeCurrencyCode = this.safeCurrencyCode (feeCurrencyId);
- fee = {
- // fee is either a positive number (invitation rebate)
- // or a negative number (transaction fee deduction)
- // therefore we need to invert the fee
- // more about it https://github.com/ccxt/ccxt/issues/5909
- 'cost': -feeCost,
- 'currency': feeCurrencyCode,
- };
- }
- const orderId = this.safeString (trade, 'order_id');
- return {
+ const orderId = this.safeString (userTrade, 'order_id');
+ const result = {
'info': pair,
'timestamp': timestamp,
'datetime': this.iso8601 (timestamp),
@@ -2665,6 +2790,10 @@ module.exports = class okex extends Exchange {
'cost': cost,
'fee': fee,
};
+ if (fees !== undefined) {
+ result['fees'] = fees;
+ }
+ return result;
}
parseMyTrades (trades, market = undefined, since = undefined, limit = undefined, params = {}) {
@@ -2704,8 +2833,8 @@ module.exports = class okex extends Exchange {
const request = {
'instrument_id': market['id'],
// 'order_id': id, // string
- // 'after': '1', // return the page after the specified page number
- // 'before': '1', // return the page before the specified page number
+ // 'after': '1', // pagination of data to return records earlier than the requested ledger_id
+ // 'before': '1', // P=pagination of data to return records newer than the requested ledger_id
// 'limit': limit, // optional, number of results per request, default = maximum = 100
};
const defaultType = this.safeString2 (this.options, 'fetchMyTrades', 'defaultType');
@@ -2797,6 +2926,277 @@ module.exports = class okex extends Exchange {
return await this.fetchMyTrades (symbol, since, limit, this.extend (request, params));
}
+ async fetchPosition (symbol, params = {}) {
+ await this.loadMarkets ();
+ const market = this.market (symbol);
+ let method = undefined;
+ const request = {
+ 'instrument_id': market['id'],
+ // 'order_id': id, // string
+ // 'after': '1', // pagination of data to return records earlier than the requested ledger_id
+ // 'before': '1', // P=pagination of data to return records newer than the requested ledger_id
+ // 'limit': limit, // optional, number of results per request, default = maximum = 100
+ };
+ const type = market['type'];
+ if ((type === 'futures') || (type === 'swap')) {
+ method = type + 'GetInstrumentIdPosition';
+ } else if (type === 'option') {
+ const underlying = this.safeString (params, 'underlying');
+ if (underlying === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchPosition() requires an underlying parameter for ' + type + ' market ' + symbol);
+ }
+ method = type + 'GetUnderlyingPosition';
+ } else {
+ throw new NotSupported (this.id + ' fetchPosition() does not support ' + type + ' market ' + symbol + ', supported market types are futures, swap or option');
+ }
+ const response = await this[method] (this.extend (request, params));
+ //
+ // futures
+ //
+ // crossed margin mode
+ //
+ // {
+ // "result": true,
+ // "holding": [
+ // {
+ // "long_qty": "2",
+ // "long_avail_qty": "2",
+ // "long_avg_cost": "8260",
+ // "long_settlement_price": "8260",
+ // "realised_pnl": "0.00020928",
+ // "short_qty": "2",
+ // "short_avail_qty": "2",
+ // "short_avg_cost": "8259.99",
+ // "short_settlement_price": "8259.99",
+ // "liquidation_price": "113.81",
+ // "instrument_id": "BTC-USD-191227",
+ // "leverage": "10",
+ // "created_at": "2019-09-25T07:58:42.129Z",
+ // "updated_at": "2019-10-08T14:02:51.029Z",
+ // "margin_mode": "crossed",
+ // "short_margin": "0.00242197",
+ // "short_pnl": "6.63E-6",
+ // "short_pnl_ratio": "0.002477997",
+ // "short_unrealised_pnl": "6.63E-6",
+ // "long_margin": "0.00242197",
+ // "long_pnl": "-6.65E-6",
+ // "long_pnl_ratio": "-0.002478",
+ // "long_unrealised_pnl": "-6.65E-6",
+ // "long_settled_pnl": "0",
+ // "short_settled_pnl": "0",
+ // "last": "8257.57"
+ // }
+ // ],
+ // "margin_mode": "crossed"
+ // }
+ //
+ // fixed margin mode
+ //
+ // {
+ // "result": true,
+ // "holding": [
+ // {
+ // "long_qty": "4",
+ // "long_avail_qty": "4",
+ // "long_margin": "0.00323844",
+ // "long_liqui_price": "7762.09",
+ // "long_pnl_ratio": "0.06052306",
+ // "long_avg_cost": "8234.43",
+ // "long_settlement_price": "8234.43",
+ // "realised_pnl": "-0.00000296",
+ // "short_qty": "2",
+ // "short_avail_qty": "2",
+ // "short_margin": "0.00241105",
+ // "short_liqui_price": "9166.74",
+ // "short_pnl_ratio": "0.03318052",
+ // "short_avg_cost": "8295.13",
+ // "short_settlement_price": "8295.13",
+ // "instrument_id": "BTC-USD-191227",
+ // "long_leverage": "15",
+ // "short_leverage": "10",
+ // "created_at": "2019-09-25T07:58:42.129Z",
+ // "updated_at": "2019-10-08T13:12:09.438Z",
+ // "margin_mode": "fixed",
+ // "short_margin_ratio": "0.10292507",
+ // "short_maint_margin_ratio": "0.005",
+ // "short_pnl": "7.853E-5",
+ // "short_unrealised_pnl": "7.853E-5",
+ // "long_margin_ratio": "0.07103743",
+ // "long_maint_margin_ratio": "0.005",
+ // "long_pnl": "1.9841E-4",
+ // "long_unrealised_pnl": "1.9841E-4",
+ // "long_settled_pnl": "0",
+ // "short_settled_pnl": "0",
+ // "last": "8266.99"
+ // }
+ // ],
+ // "margin_mode": "fixed"
+ // }
+ //
+ // swap
+ //
+ // crossed margin mode
+ //
+ // {
+ // "margin_mode": "crossed",
+ // "timestamp": "2019-09-27T03:49:02.018Z",
+ // "holding": [
+ // {
+ // "avail_position": "3",
+ // "avg_cost": "59.49",
+ // "instrument_id": "LTC-USD-SWAP",
+ // "last": "55.98",
+ // "leverage": "10.00",
+ // "liquidation_price": "4.37",
+ // "maint_margin_ratio": "0.0100",
+ // "margin": "0.0536",
+ // "position": "3",
+ // "realized_pnl": "0.0000",
+ // "unrealized_pnl": "0",
+ // "settled_pnl": "-0.0330",
+ // "settlement_price": "55.84",
+ // "side": "long",
+ // "timestamp": "2019-09-27T03:49:02.018Z"
+ // },
+ // ]
+ // }
+ //
+ // fixed margin mode
+ //
+ // {
+ // "margin_mode": "fixed",
+ // "timestamp": "2019-09-27T03:47:37.230Z",
+ // "holding": [
+ // {
+ // "avail_position": "20",
+ // "avg_cost": "8025.0",
+ // "instrument_id": "BTC-USD-SWAP",
+ // "last": "8113.1",
+ // "leverage": "15.00",
+ // "liquidation_price": "7002.6",
+ // "maint_margin_ratio": "0.0050",
+ // "margin": "0.0454",
+ // "position": "20",
+ // "realized_pnl": "-0.0001",
+ // "unrealized_pnl": "0",
+ // "settled_pnl": "0.0076",
+ // "settlement_price": "8279.2",
+ // "side": "long",
+ // "timestamp": "2019-09-27T03:47:37.230Z"
+ // }
+ // ]
+ // }
+ //
+ // option
+ //
+ // {
+ // "holding":[
+ // {
+ // "instrument_id":"BTC-USD-190927-12500-C",
+ // "position":"20",
+ // "avg_cost":"3.26",
+ // "avail_position":"20",
+ // "settlement_price":"0.017",
+ // "total_pnl":"50",
+ // "pnl_ratio":"0.3",
+ // "realized_pnl":"40",
+ // "unrealized_pnl":"10",
+ // "pos_margin":"100",
+ // "option_value":"70",
+ // "created_at":"2019-08-30T03:09:20.315Z",
+ // "updated_at":"2019-08-30T03:40:18.318Z"
+ // },
+ // {
+ // "instrument_id":"BTC-USD-190927-12500-P",
+ // "position":"20",
+ // "avg_cost":"3.26",
+ // "avail_position":"20",
+ // "settlement_price":"0.019",
+ // "total_pnl":"50",
+ // "pnl_ratio":"0.3",
+ // "realized_pnl":"40",
+ // "unrealized_pnl":"10",
+ // "pos_margin":"100",
+ // "option_value":"70",
+ // "created_at":"2019-08-30T03:09:20.315Z",
+ // "updated_at":"2019-08-30T03:40:18.318Z"
+ // }
+ // ]
+ // }
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
+ async fetchPositions (symbols = undefined, since = undefined, limit = undefined, params = {}) {
+ await this.loadMarkets ();
+ let method = undefined;
+ const defaultType = this.safeString2 (this.options, 'fetchPositions', 'defaultType');
+ const type = this.safeString (params, 'type', defaultType);
+ if ((type === 'futures') || (type === 'swap')) {
+ method = type + 'GetPosition';
+ } else if (type === 'option') {
+ const underlying = this.safeString (params, 'underlying');
+ if (underlying === undefined) {
+ throw new ArgumentsRequired (this.id + ' fetchPositions() requires an underlying parameter for ' + type + ' markets');
+ }
+ method = type + 'GetUnderlyingPosition';
+ } else {
+ throw new NotSupported (this.id + ' fetchPositions() does not support ' + type + ' markets, supported market types are futures, swap or option');
+ }
+ params = this.omit (params, 'type');
+ const response = await this[method] (params);
+ //
+ // futures
+ //
+ // ...
+ //
+ //
+ // swap
+ //
+ // ...
+ //
+ // option
+ //
+ // {
+ // "holding":[
+ // {
+ // "instrument_id":"BTC-USD-190927-12500-C",
+ // "position":"20",
+ // "avg_cost":"3.26",
+ // "avail_position":"20",
+ // "settlement_price":"0.017",
+ // "total_pnl":"50",
+ // "pnl_ratio":"0.3",
+ // "realized_pnl":"40",
+ // "unrealized_pnl":"10",
+ // "pos_margin":"100",
+ // "option_value":"70",
+ // "created_at":"2019-08-30T03:09:20.315Z",
+ // "updated_at":"2019-08-30T03:40:18.318Z"
+ // },
+ // {
+ // "instrument_id":"BTC-USD-190927-12500-P",
+ // "position":"20",
+ // "avg_cost":"3.26",
+ // "avail_position":"20",
+ // "settlement_price":"0.019",
+ // "total_pnl":"50",
+ // "pnl_ratio":"0.3",
+ // "realized_pnl":"40",
+ // "unrealized_pnl":"10",
+ // "pos_margin":"100",
+ // "option_value":"70",
+ // "created_at":"2019-08-30T03:09:20.315Z",
+ // "updated_at":"2019-08-30T03:40:18.318Z"
+ // }
+ // ]
+ // }
+ //
+ // todo unify parsePosition/parsePositions
+ return response;
+ }
+
async fetchLedger (code = undefined, since = undefined, limit = undefined, params = {}) {
await this.loadMarkets ();
const defaultType = this.safeString2 (this.options, 'fetchLedger', 'defaultType');
@@ -2987,9 +3387,17 @@ module.exports = class okex extends Exchange {
// },
// ]
//
+ const responseLength = response.length;
+ if (responseLength < 1) {
+ return [];
+ }
const isArray = Array.isArray (response[0]);
const isMargin = (type === 'margin');
const entries = (isMargin && isArray) ? response[0] : response;
+ if (type === 'swap') {
+ const ledgerEntries = this.parseLedger (entries);
+ return this.filterBySymbolSinceLimit (ledgerEntries, code, since, limit);
+ }
return this.parseLedger (entries, currency, since, limit);
}
@@ -3099,6 +3507,12 @@ module.exports = class okex extends Exchange {
const before = undefined;
const after = this.safeFloat (item, 'balance');
const status = 'ok';
+ const marketId = this.safeString (item, 'instrument_id');
+ let symbol = undefined;
+ if (marketId in this.markets_by_id) {
+ const market = this.markets_by_id[marketId];
+ symbol = market['symbol'];
+ }
return {
'info': item,
'id': id,
@@ -3107,6 +3521,7 @@ module.exports = class okex extends Exchange {
'referenceAccount': referenceAccount,
'type': type,
'currency': code,
+ 'symbol': symbol,
'amount': amount,
'before': before, // balance before
'after': after, // balance after
@@ -3154,7 +3569,7 @@ module.exports = class okex extends Exchange {
headers['Content-Type'] = 'application/json';
}
const signature = this.hmac (this.encode (auth), this.encode (this.secret), 'sha256', 'base64');
- headers['OK-ACCESS-SIGN'] = this.decode (signature);
+ headers['OK-ACCESS-SIGN'] = signature;
}
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
}
@@ -3172,25 +3587,30 @@ module.exports = class okex extends Exchange {
}
handleErrors (code, reason, url, method, headers, body, response, requestHeaders, requestBody) {
+ if (!response) {
+ return; // fallback to default error handler
+ }
const feedback = this.id + ' ' + body;
if (code === 503) {
// {"message":"name resolution failed"}
throw new ExchangeNotAvailable (feedback);
}
- if (!response) {
- return; // fallback to default error handler
- }
+ //
+ // {"error_message":"Order does not exist","result":"true","error_code":"35029","order_id":"-1"}
+ //
const message = this.safeString (response, 'message');
const errorCode = this.safeString2 (response, 'code', 'error_code');
- if (message !== undefined) {
+ const nonEmptyMessage = ((message !== undefined) && (message !== ''));
+ const nonZeroErrorCode = (errorCode !== undefined) && (errorCode !== '0');
+ if (nonEmptyMessage) {
this.throwExactlyMatchedException (this.exceptions['exact'], message, feedback);
this.throwBroadlyMatchedException (this.exceptions['broad'], message, feedback);
+ }
+ if (nonZeroErrorCode) {
this.throwExactlyMatchedException (this.exceptions['exact'], errorCode, feedback);
- const nonEmptyMessage = (message !== '');
- const nonZeroErrorCode = (errorCode !== undefined) && (errorCode !== '0');
- if (nonZeroErrorCode || nonEmptyMessage) {
- throw new ExchangeError (feedback); // unknown message
- }
+ }
+ if (nonZeroErrorCode || nonEmptyMessage) {
+ throw new ExchangeError (feedback); // unknown message
}
}
};
diff --git a/TaskServer/node_modules/ccxt/js/paymium.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/paymium.js
similarity index 89%
rename from TaskServer/node_modules/ccxt/js/paymium.js
rename to Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/paymium.js
index b46b2c369..1af0c5355 100644
--- a/TaskServer/node_modules/ccxt/js/paymium.js
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/paymium.js
@@ -17,9 +17,15 @@ module.exports = class paymium extends Exchange {
'version': 'v1',
'has': {
'CORS': true,
+ 'fetchBalance': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'fetchOrderBook': true,
+ 'createOrder': true,
+ 'cancelOrder': true,
},
'urls': {
- 'logo': 'https://user-images.githubusercontent.com/1294454/27790564-a945a9d4-5ff9-11e7-9d2d-b635763f2f24.jpg',
+ 'logo': 'https://user-images.githubusercontent.com/51840849/87153930-f0f02200-c2c0-11ea-9c0a-40337375ae89.jpg',
'api': 'https://paymium.com/api',
'www': 'https://www.paymium.com',
'fees': 'https://www.paymium.com/page/help/fees',
@@ -33,31 +39,34 @@ module.exports = class paymium extends Exchange {
'public': {
'get': [
'countries',
- 'data/{id}/ticker',
- 'data/{id}/trades',
- 'data/{id}/depth',
+ 'data/{currency}/ticker',
+ 'data/{currency}/trades',
+ 'data/{currency}/depth',
'bitcoin_charts/{id}/trades',
'bitcoin_charts/{id}/depth',
],
},
'private': {
'get': [
- 'merchant/get_payment/{uuid}',
'user',
'user/addresses',
- 'user/addresses/{btc_address}',
+ 'user/addresses/{address}',
'user/orders',
'user/orders/{uuid}',
'user/price_alerts',
+ 'merchant/get_payment/{uuid}',
],
'post': [
- 'user/orders',
'user/addresses',
+ 'user/orders',
+ 'user/withdrawals',
+ 'user/email_transfers',
'user/payment_requests',
'user/price_alerts',
'merchant/create_payment',
],
'delete': [
+ 'user/orders/{uuid}',
'user/orders/{uuid}/cancel',
'user/price_alerts/{id}',
],
@@ -98,17 +107,18 @@ module.exports = class paymium extends Exchange {
async fetchOrderBook (symbol, limit = undefined, params = {}) {
await this.loadMarkets ();
const request = {
- 'id': this.marketId (symbol),
+ 'currency': this.marketId (symbol),
};
- const response = await this.publicGetDataIdDepth (this.extend (request, params));
+ const response = await this.publicGetDataCurrencyDepth (this.extend (request, params));
return this.parseOrderBook (response, undefined, 'bids', 'asks', 'price', 'amount');
}
async fetchTicker (symbol, params = {}) {
+ await this.loadMarkets ();
const request = {
- 'id': this.marketId (symbol),
+ 'currency': this.marketId (symbol),
};
- const ticker = await this.publicGetDataIdTicker (this.extend (request, params));
+ const ticker = await this.publicGetDataCurrencyTicker (this.extend (request, params));
const timestamp = this.safeTimestamp (ticker, 'at');
const vwap = this.safeFloat (ticker, 'vwap');
const baseVolume = this.safeFloat (ticker, 'volume');
@@ -179,9 +189,9 @@ module.exports = class paymium extends Exchange {
await this.loadMarkets ();
const market = this.market (symbol);
const request = {
- 'id': market['id'],
+ 'currency': market['id'],
};
- const response = await this.publicGetDataIdTrades (this.extend (request, params));
+ const response = await this.publicGetDataCurrencyTrades (this.extend (request, params));
return this.parseTrades (response, market, since, limit);
}
diff --git a/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/phemex.js b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/phemex.js
new file mode 100644
index 000000000..5fa317455
--- /dev/null
+++ b/Projects/Superalgos/TS/Bot-Modules/Trading-Bot/Low-Frequency-Trading/APIs/node_modules/ccxt/js/phemex.js
@@ -0,0 +1,2505 @@
+'use strict';
+
+// ----------------------------------------------------------------------------
+
+const Exchange = require ('./base/Exchange');
+const { ExchangeError, BadSymbol, AuthenticationError, InsufficientFunds, InvalidOrder, ArgumentsRequired, OrderNotFound, BadRequest, PermissionDenied, AccountSuspended, CancelPending, DDoSProtection, DuplicateOrderId, NotSupported } = require ('./base/errors');
+const { TICK_SIZE, ROUND, DECIMAL_PLACES } = require ('./base/functions/number');
+
+// ----------------------------------------------------------------------------
+
+module.exports = class phemex extends Exchange {
+ describe () {
+ return this.deepExtend (super.describe (), {
+ 'id': 'phemex',
+ 'name': 'Phemex',
+ 'countries': [ 'CN' ], // China
+ 'rateLimit': 100,
+ 'version': 'v1',
+ 'certified': false,
+ 'pro': true,
+ 'has': {
+ 'cancelAllOrders': true, // swap contracts only
+ 'cancelOrder': true,
+ 'createOrder': true,
+ 'fetchBalance': true,
+ 'fetchClosedOrders': true,
+ 'fetchCurrencies': true,
+ 'fetchDepositAddress': true,
+ 'fetchDeposits': true,
+ 'fetchMarkets': true,
+ 'fetchMyTrades': true,
+ 'fetchOHLCV': true,
+ 'fetchOpenOrders': true,
+ 'fetchOrder': true,
+ 'fetchOrderBook': true,
+ 'fetchOrders': true,
+ 'fetchTicker': true,
+ 'fetchTrades': true,
+ 'fetchWithdrawals': true,
+ },
+ 'urls': {
+ 'logo': 'https://user-images.githubusercontent.com/1294454/85225056-221eb600-b3d7-11ea-930d-564d2690e3f6.jpg',
+ 'test': {
+ 'v1': 'https://testnet-api.phemex.com/v1',
+ 'public': 'https://testnet-api.phemex.com/exchange/public',
+ 'private': 'https://testnet-api.phemex.com',
+ },
+ 'api': {
+ 'v1': 'https://api.phemex.com/v1',
+ 'public': 'https://api.phemex.com/exchange/public',
+ 'private': 'https://api.phemex.com',
+ },
+ 'www': 'https://phemex.com',
+ 'doc': 'https://github.com/phemex/phemex-api-docs',
+ 'fees': 'https://phemex.com/fees-conditions',
+ 'referral': 'https://phemex.com/register?referralCode=EDNVJ',
+ },
+ 'timeframes': {
+ '1m': '60',
+ '3m': '180',
+ '5m': '300',
+ '15m': '900',
+ '30m': '1800',
+ '1h': '3600',
+ '2h': '7200',
+ '3h': '10800',
+ '4h': '14400',
+ '6h': '21600',
+ '12h': '43200',
+ '1d': '86400',
+ '1w': '604800',
+ '1M': '2592000',
+ },
+ 'api': {
+ 'public': {
+ 'get': [
+ 'cfg/v2/products', // spot + contracts
+ 'products', // contracts only
+ 'nomics/trades', // ?market=&since=
+ 'md/kline', // ?from=1589811875&resolution=1800&symbol=sBTCUSDT&to=1592457935
+ ],
+ },
+ 'v1': {
+ 'get': [
+ 'md/orderbook', // ?symbol=&id=
+ 'md/trade', // ?symbol=&id=
+ 'md/ticker/24hr', // ?symbol=&id=
+ 'md/ticker/24hr/all', // ?id=
+ 'md/spot/ticker/24hr', // ?symbol=&id=
+ 'md/spot/ticker/24hr/all', // ?symbol=&id=
+ 'exchange/public/products', // contracts only
+ ],
+ },
+ 'private': {
+ 'get': [
+ // spot
+ 'spot/orders/active', // ?symbol=&orderID=
+ // 'spot/orders/active', // ?symbol=&clOrDID=
+ 'spot/orders', // ?symbol=
+ 'spot/wallets', // ?currency=
+ 'exchange/spot/order', // ?symbol=&ordStatus=ordType=&start=&end=&limit=&offset=
+ 'exchange/spot/order/trades', // ?symbol=&start=&end=&limit=&offset=
+ // swap
+ 'accounts/accountPositions', // ?currency=
+ 'orders/activeList', // ?symbol=
+ 'exchange/order/list', // ?symbol=&start=&end=&offset=&limit=&ordStatus=&withCount=
+ 'exchange/order', // ?symbol=&orderID=
+ // 'exchange/order', // ?symbol=&clOrdID=
+ 'exchange/order/trade', // ?symbol=&start=&end=&limit=&offset=&withCount=
+ 'phemex-user/users/children', // ?offset=&limit=&withCount=
+ 'phemex-user/wallets/v2/depositAddress', // ?_t=1592722635531¤cy=USDT
+ 'exchange/margins/transfer', // ?start=&end=&offset=&limit=&withCount=
+ 'exchange/wallets/confirm/withdraw', // ?code=
+ 'exchange/wallets/withdrawList', // ?currency=&limit=