ccxt 4.2.11 → 4.2.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -5
- package/build.sh +2 -2
- package/dist/ccxt.browser.js +1347 -490
- package/dist/ccxt.browser.min.js +3 -3
- package/dist/cjs/_virtual/agent.js +7 -0
- package/dist/cjs/_virtual/parse-proxy-response.js +7 -0
- package/dist/cjs/_virtual/promisify.js +7 -0
- package/dist/cjs/ccxt.js +1 -1
- package/dist/cjs/js/ccxt.js +474 -0
- package/dist/cjs/js/src/abstract/ace.js +9 -0
- package/dist/cjs/js/src/abstract/alpaca.js +9 -0
- package/dist/cjs/js/src/abstract/ascendex.js +9 -0
- package/dist/cjs/js/src/abstract/bigone.js +9 -0
- package/dist/cjs/js/src/abstract/binance.js +9 -0
- package/dist/cjs/js/src/abstract/bingx.js +9 -0
- package/dist/cjs/js/src/abstract/bit2c.js +9 -0
- package/dist/cjs/js/src/abstract/bitbank.js +9 -0
- package/dist/cjs/js/src/abstract/bitbns.js +9 -0
- package/dist/cjs/js/src/abstract/bitfinex.js +9 -0
- package/dist/cjs/js/src/abstract/bitfinex2.js +9 -0
- package/dist/cjs/js/src/abstract/bitflyer.js +9 -0
- package/dist/cjs/js/src/abstract/bitforex.js +9 -0
- package/dist/cjs/js/src/abstract/bitget.js +9 -0
- package/dist/cjs/js/src/abstract/bithumb.js +9 -0
- package/dist/cjs/js/src/abstract/bitmart.js +9 -0
- package/dist/cjs/js/src/abstract/bitmex.js +9 -0
- package/dist/cjs/js/src/abstract/bitopro.js +9 -0
- package/dist/cjs/js/src/abstract/bitpanda.js +9 -0
- package/dist/cjs/js/src/abstract/bitrue.js +9 -0
- package/dist/cjs/js/src/abstract/bitso.js +9 -0
- package/dist/cjs/js/src/abstract/bitstamp.js +9 -0
- package/dist/cjs/js/src/abstract/bitteam.js +9 -0
- package/dist/cjs/js/src/abstract/bitvavo.js +9 -0
- package/dist/cjs/js/src/abstract/bl3p.js +9 -0
- package/dist/cjs/js/src/abstract/blockchaincom.js +9 -0
- package/dist/cjs/js/src/abstract/btcalpha.js +9 -0
- package/dist/cjs/js/src/abstract/btcbox.js +9 -0
- package/dist/cjs/js/src/abstract/btcmarkets.js +9 -0
- package/dist/cjs/js/src/abstract/btcturk.js +9 -0
- package/dist/cjs/js/src/abstract/bybit.js +9 -0
- package/dist/cjs/js/src/abstract/cex.js +9 -0
- package/dist/cjs/js/src/abstract/coinbase.js +9 -0
- package/dist/cjs/js/src/abstract/coinbasepro.js +9 -0
- package/dist/cjs/js/src/abstract/coincheck.js +9 -0
- package/dist/cjs/js/src/abstract/coinex.js +9 -0
- package/dist/cjs/js/src/abstract/coinlist.js +9 -0
- package/dist/cjs/js/src/abstract/coinmate.js +9 -0
- package/dist/cjs/js/src/abstract/coinone.js +9 -0
- package/dist/cjs/js/src/abstract/coinsph.js +9 -0
- package/dist/cjs/js/src/abstract/coinspot.js +9 -0
- package/dist/cjs/js/src/abstract/cryptocom.js +9 -0
- package/dist/cjs/js/src/abstract/currencycom.js +9 -0
- package/dist/cjs/js/src/abstract/delta.js +9 -0
- package/dist/cjs/js/src/abstract/deribit.js +9 -0
- package/dist/cjs/js/src/abstract/digifinex.js +9 -0
- package/dist/cjs/js/src/abstract/exmo.js +9 -0
- package/dist/cjs/js/src/abstract/gate.js +9 -0
- package/dist/cjs/js/src/abstract/gemini.js +9 -0
- package/dist/cjs/js/src/abstract/hitbtc.js +9 -0
- package/dist/cjs/js/src/abstract/hollaex.js +9 -0
- package/dist/cjs/js/src/abstract/htx.js +9 -0
- package/dist/cjs/js/src/abstract/huobijp.js +9 -0
- package/dist/cjs/js/src/abstract/idex.js +9 -0
- package/dist/cjs/js/src/abstract/independentreserve.js +9 -0
- package/dist/cjs/js/src/abstract/indodax.js +9 -0
- package/dist/cjs/js/src/abstract/kraken.js +9 -0
- package/dist/cjs/js/src/abstract/krakenfutures.js +9 -0
- package/dist/cjs/js/src/abstract/kucoin.js +9 -0
- package/dist/cjs/js/src/abstract/kucoinfutures.js +9 -0
- package/dist/cjs/js/src/abstract/kuna.js +9 -0
- package/dist/cjs/js/src/abstract/latoken.js +9 -0
- package/dist/cjs/js/src/abstract/lbank.js +9 -0
- package/dist/cjs/js/src/abstract/luno.js +9 -0
- package/dist/cjs/js/src/abstract/lykke.js +9 -0
- package/dist/cjs/js/src/abstract/mercado.js +9 -0
- package/dist/cjs/js/src/abstract/mexc.js +9 -0
- package/dist/cjs/js/src/abstract/ndax.js +9 -0
- package/dist/cjs/js/src/abstract/novadax.js +9 -0
- package/dist/cjs/js/src/abstract/oceanex.js +9 -0
- package/dist/cjs/js/src/abstract/okcoin.js +9 -0
- package/dist/cjs/js/src/abstract/okx.js +9 -0
- package/dist/cjs/js/src/abstract/p2b.js +9 -0
- package/dist/cjs/js/src/abstract/paymium.js +9 -0
- package/dist/cjs/js/src/abstract/phemex.js +9 -0
- package/dist/cjs/js/src/abstract/poloniex.js +9 -0
- package/dist/cjs/js/src/abstract/poloniexfutures.js +9 -0
- package/dist/cjs/js/src/abstract/probit.js +9 -0
- package/dist/cjs/js/src/abstract/timex.js +9 -0
- package/dist/cjs/js/src/abstract/tokocrypto.js +9 -0
- package/dist/cjs/js/src/abstract/upbit.js +9 -0
- package/dist/cjs/js/src/abstract/wavesexchange.js +9 -0
- package/dist/cjs/js/src/abstract/wazirx.js +9 -0
- package/dist/cjs/js/src/abstract/whitebit.js +9 -0
- package/dist/cjs/js/src/abstract/woo.js +9 -0
- package/dist/cjs/js/src/abstract/yobit.js +9 -0
- package/dist/cjs/js/src/abstract/zaif.js +9 -0
- package/dist/cjs/js/src/abstract/zonda.js +9 -0
- package/dist/cjs/js/src/ace.js +1058 -0
- package/dist/cjs/js/src/alpaca.js +1125 -0
- package/dist/cjs/js/src/ascendex.js +3360 -0
- package/dist/cjs/js/src/base/Exchange.js +5110 -0
- package/dist/cjs/js/src/base/Precise.js +263 -0
- package/dist/cjs/js/src/base/errors.js +299 -0
- package/dist/cjs/js/src/base/functions/crypto.js +78 -0
- package/dist/cjs/js/src/base/functions/encode.js +44 -0
- package/dist/cjs/js/src/base/functions/generic.js +193 -0
- package/dist/cjs/js/src/base/functions/misc.js +96 -0
- package/dist/cjs/js/src/base/functions/number.js +297 -0
- package/dist/cjs/js/src/base/functions/platform.js +28 -0
- package/dist/cjs/js/src/base/functions/rsa.js +34 -0
- package/dist/cjs/js/src/base/functions/string.js +48 -0
- package/dist/cjs/js/src/base/functions/throttle.js +66 -0
- package/dist/cjs/js/src/base/functions/time.js +187 -0
- package/dist/cjs/js/src/base/functions/totp.js +24 -0
- package/dist/cjs/js/src/base/functions/type.js +162 -0
- package/dist/cjs/js/src/base/functions.js +157 -0
- package/dist/cjs/js/src/base/ws/Cache.js +254 -0
- package/dist/cjs/js/src/base/ws/Client.js +299 -0
- package/dist/cjs/js/src/base/ws/Future.js +34 -0
- package/dist/cjs/js/src/base/ws/OrderBook.js +107 -0
- package/dist/cjs/js/src/base/ws/OrderBookSide.js +281 -0
- package/dist/cjs/js/src/base/ws/WsClient.js +69 -0
- package/dist/cjs/js/src/bequant.js +33 -0
- package/dist/cjs/js/src/bigone.js +2209 -0
- package/dist/cjs/js/src/binance.js +9736 -0
- package/dist/cjs/js/src/binancecoinm.js +45 -0
- package/dist/cjs/js/src/binanceus.js +84 -0
- package/dist/cjs/js/src/binanceusdm.js +58 -0
- package/dist/cjs/js/src/bingx.js +3807 -0
- package/dist/cjs/js/src/bit2c.js +916 -0
- package/dist/cjs/js/src/bitbank.js +1000 -0
- package/dist/cjs/js/src/bitbay.js +17 -0
- package/dist/cjs/js/src/bitbns.js +1220 -0
- package/dist/cjs/js/src/bitcoincom.js +17 -0
- package/dist/cjs/js/src/bitfinex.js +1670 -0
- package/dist/cjs/js/src/bitfinex2.js +2990 -0
- package/dist/cjs/js/src/bitflyer.js +1045 -0
- package/dist/cjs/js/src/bitforex.js +852 -0
- package/dist/cjs/js/src/bitget.js +8291 -0
- package/dist/cjs/js/src/bithumb.js +1090 -0
- package/dist/cjs/js/src/bitmart.js +4454 -0
- package/dist/cjs/js/src/bitmex.js +2884 -0
- package/dist/cjs/js/src/bitopro.js +1724 -0
- package/dist/cjs/js/src/bitpanda.js +2002 -0
- package/dist/cjs/js/src/bitrue.js +3253 -0
- package/dist/cjs/js/src/bitso.js +1753 -0
- package/dist/cjs/js/src/bitstamp.js +2188 -0
- package/dist/cjs/js/src/bitteam.js +2309 -0
- package/dist/cjs/js/src/bitvavo.js +1968 -0
- package/dist/cjs/js/src/bl3p.js +447 -0
- package/dist/cjs/js/src/blockchaincom.js +1160 -0
- package/dist/cjs/js/src/btcalpha.js +929 -0
- package/dist/cjs/js/src/btcbox.js +565 -0
- package/dist/cjs/js/src/btcmarkets.js +1237 -0
- package/dist/cjs/js/src/btcturk.js +929 -0
- package/dist/cjs/js/src/bybit.js +7646 -0
- package/dist/cjs/js/src/cex.js +1693 -0
- package/dist/cjs/js/src/coinbase.js +3424 -0
- package/dist/cjs/js/src/coinbasepro.js +1866 -0
- package/dist/cjs/js/src/coincheck.js +843 -0
- package/dist/cjs/js/src/coinex.js +5414 -0
- package/dist/cjs/js/src/coinlist.js +2329 -0
- package/dist/cjs/js/src/coinmate.js +989 -0
- package/dist/cjs/js/src/coinone.js +1185 -0
- package/dist/cjs/js/src/coinsph.js +1933 -0
- package/dist/cjs/js/src/coinspot.js +548 -0
- package/dist/cjs/js/src/cryptocom.js +3007 -0
- package/dist/cjs/js/src/currencycom.js +2015 -0
- package/dist/cjs/js/src/delta.js +3256 -0
- package/dist/cjs/js/src/deribit.js +3306 -0
- package/dist/cjs/js/src/digifinex.js +4307 -0
- package/dist/cjs/js/src/exmo.js +2645 -0
- package/dist/cjs/js/src/fmfwio.js +34 -0
- package/dist/cjs/js/src/gate.js +7072 -0
- package/dist/cjs/js/src/gateio.js +16 -0
- package/dist/cjs/js/src/gemini.js +1801 -0
- package/dist/cjs/js/src/hitbtc.js +3660 -0
- package/dist/cjs/js/src/hitbtc3.js +19 -0
- package/dist/cjs/js/src/hollaex.js +1882 -0
- package/dist/cjs/js/src/htx.js +9049 -0
- package/dist/cjs/js/src/huobi.js +16 -0
- package/dist/cjs/js/src/huobijp.js +1918 -0
- package/dist/cjs/js/src/idex.js +1770 -0
- package/dist/cjs/js/src/independentreserve.js +761 -0
- package/dist/cjs/js/src/indodax.js +1069 -0
- package/dist/cjs/js/src/kraken.js +2857 -0
- package/dist/cjs/js/src/krakenfutures.js +2407 -0
- package/dist/cjs/js/src/kucoin.js +4489 -0
- package/dist/cjs/js/src/kucoinfutures.js +2475 -0
- package/dist/cjs/js/src/kuna.js +1949 -0
- package/dist/cjs/js/src/latoken.js +1729 -0
- package/dist/cjs/js/src/lbank.js +2851 -0
- package/dist/cjs/js/src/luno.js +1044 -0
- package/dist/cjs/js/src/lykke.js +1303 -0
- package/dist/cjs/js/src/mercado.js +897 -0
- package/dist/cjs/js/src/mexc.js +5407 -0
- package/dist/cjs/js/src/ndax.js +2450 -0
- package/dist/cjs/js/src/novadax.js +1556 -0
- package/dist/cjs/js/src/oceanex.js +964 -0
- package/dist/cjs/js/src/okcoin.js +3115 -0
- package/dist/cjs/js/src/okx.js +7330 -0
- package/dist/cjs/js/src/p2b.js +1243 -0
- package/dist/cjs/js/src/paymium.js +597 -0
- package/dist/cjs/js/src/phemex.js +4722 -0
- package/dist/cjs/js/src/poloniex.js +2356 -0
- package/dist/cjs/js/src/poloniexfutures.js +1794 -0
- package/dist/cjs/js/src/pro/alpaca.js +714 -0
- package/dist/cjs/js/src/pro/ascendex.js +957 -0
- package/dist/cjs/js/src/pro/bequant.js +33 -0
- package/dist/cjs/js/src/pro/binance.js +2796 -0
- package/dist/cjs/js/src/pro/binancecoinm.js +23 -0
- package/dist/cjs/js/src/pro/binanceus.js +51 -0
- package/dist/cjs/js/src/pro/binanceusdm.js +32 -0
- package/dist/cjs/js/src/pro/bingx.js +944 -0
- package/dist/cjs/js/src/pro/bitcoincom.js +29 -0
- package/dist/cjs/js/src/pro/bitfinex.js +672 -0
- package/dist/cjs/js/src/pro/bitfinex2.js +1159 -0
- package/dist/cjs/js/src/pro/bitget.js +1733 -0
- package/dist/cjs/js/src/pro/bitmart.js +1486 -0
- package/dist/cjs/js/src/pro/bitmex.js +1576 -0
- package/dist/cjs/js/src/pro/bitopro.js +327 -0
- package/dist/cjs/js/src/pro/bitpanda.js +1341 -0
- package/dist/cjs/js/src/pro/bitrue.js +462 -0
- package/dist/cjs/js/src/pro/bitstamp.js +547 -0
- package/dist/cjs/js/src/pro/bitvavo.js +704 -0
- package/dist/cjs/js/src/pro/blockchaincom.js +794 -0
- package/dist/cjs/js/src/pro/bybit.js +1843 -0
- package/dist/cjs/js/src/pro/cex.js +1510 -0
- package/dist/cjs/js/src/pro/coinbase.js +561 -0
- package/dist/cjs/js/src/pro/coinbasepro.js +968 -0
- package/dist/cjs/js/src/pro/coinex.js +1095 -0
- package/dist/cjs/js/src/pro/cryptocom.js +1020 -0
- package/dist/cjs/js/src/pro/currencycom.js +563 -0
- package/dist/cjs/js/src/pro/deribit.js +825 -0
- package/dist/cjs/js/src/pro/exmo.js +658 -0
- package/dist/cjs/js/src/pro/gate.js +1316 -0
- package/dist/cjs/js/src/pro/gateio.js +16 -0
- package/dist/cjs/js/src/pro/gemini.js +649 -0
- package/dist/cjs/js/src/pro/hitbtc.js +1293 -0
- package/dist/cjs/js/src/pro/hollaex.js +597 -0
- package/dist/cjs/js/src/pro/htx.js +2383 -0
- package/dist/cjs/js/src/pro/huobi.js +16 -0
- package/dist/cjs/js/src/pro/huobijp.js +606 -0
- package/dist/cjs/js/src/pro/idex.js +714 -0
- package/dist/cjs/js/src/pro/independentreserve.js +280 -0
- package/dist/cjs/js/src/pro/kraken.js +1364 -0
- package/dist/cjs/js/src/pro/krakenfutures.js +1500 -0
- package/dist/cjs/js/src/pro/kucoin.js +1052 -0
- package/dist/cjs/js/src/pro/kucoinfutures.js +981 -0
- package/dist/cjs/js/src/pro/luno.js +322 -0
- package/dist/cjs/js/src/pro/mexc.js +1170 -0
- package/dist/cjs/js/src/pro/ndax.js +545 -0
- package/dist/cjs/js/src/pro/okcoin.js +760 -0
- package/dist/cjs/js/src/pro/okx.js +1608 -0
- package/dist/cjs/js/src/pro/phemex.js +1511 -0
- package/dist/cjs/js/src/pro/poloniex.js +1253 -0
- package/dist/cjs/js/src/pro/poloniexfutures.js +1014 -0
- package/dist/cjs/js/src/pro/probit.js +586 -0
- package/dist/cjs/js/src/pro/upbit.js +234 -0
- package/dist/cjs/js/src/pro/wazirx.js +776 -0
- package/dist/cjs/js/src/pro/whitebit.js +927 -0
- package/dist/cjs/js/src/pro/woo.js +769 -0
- package/dist/cjs/js/src/probit.js +1867 -0
- package/dist/cjs/js/src/static_dependencies/fflake/browser.js +401 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/JSEncrypt.js +195 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/JSEncryptRSAKey.js +308 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/asn1js/asn1.js +554 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/asn1js/base64.js +94 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/asn1js/hex.js +70 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/asn1js/int10.js +91 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/base64.js +16 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/jsbn.js +1760 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/prng4.js +52 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/rng.js +81 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/rsa.js +376 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsbn/util.js +70 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsrsasign/asn1-1.0.js +1580 -0
- package/dist/cjs/js/src/static_dependencies/jsencrypt/lib/jsrsasign/yahoo.js +74 -0
- package/dist/cjs/js/src/static_dependencies/noble-curves/_shortw_utils.js +24 -0
- package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/curve.js +158 -0
- package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/edwards.js +429 -0
- package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/hash-to-curve.js +176 -0
- package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/modular.js +324 -0
- package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/montgomery.js +163 -0
- package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/utils.js +245 -0
- package/dist/cjs/js/src/static_dependencies/noble-curves/abstract/weierstrass.js +1018 -0
- package/dist/cjs/js/src/static_dependencies/noble-curves/ed25519.js +383 -0
- package/dist/cjs/js/src/static_dependencies/noble-curves/secp256k1.js +258 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/_assert.js +53 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/_sha2.js +120 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/_u64.js +69 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/crypto.js +7 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/hmac.js +83 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/md5.js +240 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/sha1.js +91 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/sha256.js +130 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/sha3.js +214 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/sha512.js +239 -0
- package/dist/cjs/js/src/static_dependencies/noble-hashes/utils.js +93 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/body.js +354 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/errors/abort-error.js +16 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/errors/base.js +20 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/errors/fetch-error.js +30 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/headers.js +239 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/index.js +372 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/request.js +273 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/response.js +139 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/utils/get-search.js +14 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/utils/is-redirect.js +16 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/utils/is.js +81 -0
- package/dist/cjs/js/src/static_dependencies/node-fetch/utils/referrer.js +292 -0
- package/dist/cjs/js/src/static_dependencies/proxies/agent-base/index.js +103 -0
- package/dist/cjs/js/src/static_dependencies/proxies/http-proxy-agent/index.js +140 -0
- package/dist/cjs/js/src/static_dependencies/proxies/https-proxy-agent/index.js +175 -0
- package/dist/cjs/js/src/static_dependencies/proxies/https-proxy-agent/parse-proxy-response.js +95 -0
- package/dist/cjs/js/src/static_dependencies/qs/index.cjs.js +7 -0
- package/dist/cjs/js/src/static_dependencies/scure-base/index.js +383 -0
- package/dist/cjs/js/src/timex.js +1562 -0
- package/dist/cjs/js/src/tokocrypto.js +2542 -0
- package/dist/cjs/js/src/upbit.js +1844 -0
- package/dist/cjs/js/src/wavesexchange.js +2607 -0
- package/dist/cjs/js/src/wazirx.js +953 -0
- package/dist/cjs/js/src/whitebit.js +2309 -0
- package/dist/cjs/js/src/woo.js +2765 -0
- package/dist/cjs/js/src/yobit.js +1314 -0
- package/dist/cjs/js/src/zaif.js +736 -0
- package/dist/cjs/js/src/zonda.js +1883 -0
- package/js/ccxt.d.ts +1 -1
- package/js/ccxt.js +1 -1
- package/js/src/abstract/bigone.d.ts +18 -0
- package/js/src/abstract/binance.d.ts +2 -0
- package/js/src/abstract/binancecoinm.d.ts +2 -0
- package/js/src/abstract/binanceus.d.ts +2 -0
- package/js/src/abstract/binanceusdm.d.ts +2 -0
- package/js/src/abstract/bingx.d.ts +2 -0
- package/js/src/abstract/bybit.d.ts +1 -0
- package/js/src/abstract/gate.d.ts +11 -0
- package/js/src/abstract/gateio.d.ts +11 -0
- package/js/src/abstract/okx.d.ts +1 -0
- package/js/src/alpaca.js +18 -18
- package/js/src/base/Exchange.d.ts +5 -1
- package/js/src/base/Exchange.js +101 -12
- package/js/src/bigone.d.ts +3 -2
- package/js/src/bigone.js +429 -167
- package/js/src/binance.js +48 -34
- package/js/src/bingx.js +115 -38
- package/js/src/bitfinex.d.ts +2 -2
- package/js/src/bitfinex.js +2 -3
- package/js/src/bitget.js +33 -13
- package/js/src/bitmart.d.ts +2 -2
- package/js/src/bitmart.js +5 -5
- package/js/src/bitmex.js +1 -0
- package/js/src/bybit.js +2 -0
- package/js/src/coinbase.d.ts +26 -3
- package/js/src/coinbase.js +176 -26
- package/js/src/coinlist.js +3 -4
- package/js/src/coinone.js +1 -1
- package/js/src/coinsph.js +2 -3
- package/js/src/deribit.js +1 -0
- package/js/src/gate.d.ts +4 -4
- package/js/src/gate.js +96 -59
- package/js/src/gemini.js +1 -1
- package/js/src/hitbtc.d.ts +4 -4
- package/js/src/hitbtc.js +2 -3
- package/js/src/htx.d.ts +1 -0
- package/js/src/htx.js +29 -7
- package/js/src/huobijp.js +2 -3
- package/js/src/independentreserve.js +7 -5
- package/js/src/kraken.js +3 -6
- package/js/src/lbank.js +59 -33
- package/js/src/mexc.js +2 -1
- package/js/src/oceanex.js +1 -1
- package/js/src/okx.js +14 -3
- package/js/src/phemex.js +9 -2
- package/js/src/pro/binance.d.ts +2 -23
- package/js/src/pro/binance.js +58 -22
- package/js/src/pro/coinbase.d.ts +2 -2
- package/js/src/pro/coinbase.js +4 -1
- package/js/src/pro/coinbasepro.d.ts +2 -2
- package/js/src/pro/hitbtc.d.ts +2 -2
- package/js/src/pro/kraken.js +1 -1
- package/js/src/pro/okx.d.ts +1 -0
- package/js/src/pro/okx.js +52 -2
- package/js/src/pro/poloniex.d.ts +2 -2
- package/js/src/probit.js +4 -2
- package/js/src/upbit.d.ts +3 -101
- package/js/src/upbit.js +12 -12
- package/js/src/wavesexchange.js +1 -1
- package/js/src/woo.d.ts +2 -0
- package/js/src/woo.js +52 -0
- package/package.json +1 -1
- package/skip-tests.json +5 -0
|
@@ -0,0 +1,2645 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var exmo$1 = require('./abstract/exmo.js');
|
|
4
|
+
var errors = require('./base/errors.js');
|
|
5
|
+
var Precise = require('./base/Precise.js');
|
|
6
|
+
var number = require('./base/functions/number.js');
|
|
7
|
+
var sha512 = require('./static_dependencies/noble-hashes/sha512.js');
|
|
8
|
+
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
/**
|
|
12
|
+
* @class exmo
|
|
13
|
+
* @augments Exchange
|
|
14
|
+
*/
|
|
15
|
+
class exmo extends exmo$1 {
|
|
16
|
+
describe() {
|
|
17
|
+
return this.deepExtend(super.describe(), {
|
|
18
|
+
'id': 'exmo',
|
|
19
|
+
'name': 'EXMO',
|
|
20
|
+
'countries': ['LT'],
|
|
21
|
+
'rateLimit': 350,
|
|
22
|
+
'version': 'v1.1',
|
|
23
|
+
'has': {
|
|
24
|
+
'CORS': undefined,
|
|
25
|
+
'spot': true,
|
|
26
|
+
'margin': true,
|
|
27
|
+
'swap': false,
|
|
28
|
+
'future': false,
|
|
29
|
+
'option': false,
|
|
30
|
+
'addMargin': true,
|
|
31
|
+
'cancelOrder': true,
|
|
32
|
+
'cancelOrders': false,
|
|
33
|
+
'createDepositAddress': false,
|
|
34
|
+
'createOrder': true,
|
|
35
|
+
'createStopLimitOrder': true,
|
|
36
|
+
'createStopMarketOrder': true,
|
|
37
|
+
'createStopOrder': true,
|
|
38
|
+
'editOrder': true,
|
|
39
|
+
'fetchAccounts': false,
|
|
40
|
+
'fetchBalance': true,
|
|
41
|
+
'fetchCanceledOrders': true,
|
|
42
|
+
'fetchCurrencies': true,
|
|
43
|
+
'fetchDeposit': true,
|
|
44
|
+
'fetchDepositAddress': true,
|
|
45
|
+
'fetchDeposits': true,
|
|
46
|
+
'fetchDepositsWithdrawals': true,
|
|
47
|
+
'fetchDepositWithdrawFee': 'emulated',
|
|
48
|
+
'fetchDepositWithdrawFees': true,
|
|
49
|
+
'fetchFundingHistory': false,
|
|
50
|
+
'fetchFundingRate': false,
|
|
51
|
+
'fetchFundingRateHistory': false,
|
|
52
|
+
'fetchFundingRates': false,
|
|
53
|
+
'fetchIndexOHLCV': false,
|
|
54
|
+
'fetchMarginMode': false,
|
|
55
|
+
'fetchMarkets': true,
|
|
56
|
+
'fetchMarkOHLCV': false,
|
|
57
|
+
'fetchMyTrades': true,
|
|
58
|
+
'fetchOHLCV': true,
|
|
59
|
+
'fetchOpenInterestHistory': false,
|
|
60
|
+
'fetchOpenOrders': true,
|
|
61
|
+
'fetchOrder': 'emulated',
|
|
62
|
+
'fetchOrderBook': true,
|
|
63
|
+
'fetchOrderBooks': true,
|
|
64
|
+
'fetchOrderTrades': true,
|
|
65
|
+
'fetchPositionMode': false,
|
|
66
|
+
'fetchPremiumIndexOHLCV': false,
|
|
67
|
+
'fetchTicker': true,
|
|
68
|
+
'fetchTickers': true,
|
|
69
|
+
'fetchTrades': true,
|
|
70
|
+
'fetchTradingFee': false,
|
|
71
|
+
'fetchTradingFees': true,
|
|
72
|
+
'fetchTransactionFees': true,
|
|
73
|
+
'fetchTransactions': 'emulated',
|
|
74
|
+
'fetchTransfer': false,
|
|
75
|
+
'fetchTransfers': false,
|
|
76
|
+
'fetchWithdrawal': true,
|
|
77
|
+
'fetchWithdrawals': true,
|
|
78
|
+
'reduceMargin': true,
|
|
79
|
+
'setMargin': false,
|
|
80
|
+
'transfer': false,
|
|
81
|
+
'withdraw': true,
|
|
82
|
+
},
|
|
83
|
+
'timeframes': {
|
|
84
|
+
'1m': '1',
|
|
85
|
+
'5m': '5',
|
|
86
|
+
'15m': '15',
|
|
87
|
+
'30m': '30',
|
|
88
|
+
'45m': '45',
|
|
89
|
+
'1h': '60',
|
|
90
|
+
'2h': '120',
|
|
91
|
+
'3h': '180',
|
|
92
|
+
'4h': '240',
|
|
93
|
+
'1d': 'D',
|
|
94
|
+
'1w': 'W',
|
|
95
|
+
'1M': 'M',
|
|
96
|
+
},
|
|
97
|
+
'urls': {
|
|
98
|
+
'logo': 'https://user-images.githubusercontent.com/1294454/27766491-1b0ea956-5eda-11e7-9225-40d67b481b8d.jpg',
|
|
99
|
+
'api': {
|
|
100
|
+
'public': 'https://api.exmo.com',
|
|
101
|
+
'private': 'https://api.exmo.com',
|
|
102
|
+
'web': 'https://exmo.me',
|
|
103
|
+
},
|
|
104
|
+
'www': 'https://exmo.me',
|
|
105
|
+
'referral': 'https://exmo.me/?ref=131685',
|
|
106
|
+
'doc': [
|
|
107
|
+
'https://exmo.me/en/api_doc?ref=131685',
|
|
108
|
+
],
|
|
109
|
+
'fees': 'https://exmo.com/en/docs/fees',
|
|
110
|
+
},
|
|
111
|
+
'api': {
|
|
112
|
+
'web': {
|
|
113
|
+
'get': [
|
|
114
|
+
'ctrl/feesAndLimits',
|
|
115
|
+
'en/docs/fees',
|
|
116
|
+
],
|
|
117
|
+
},
|
|
118
|
+
'public': {
|
|
119
|
+
'get': [
|
|
120
|
+
'currency',
|
|
121
|
+
'currency/list/extended',
|
|
122
|
+
'order_book',
|
|
123
|
+
'pair_settings',
|
|
124
|
+
'ticker',
|
|
125
|
+
'trades',
|
|
126
|
+
'candles_history',
|
|
127
|
+
'required_amount',
|
|
128
|
+
'payments/providers/crypto/list',
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
'private': {
|
|
132
|
+
'post': [
|
|
133
|
+
'user_info',
|
|
134
|
+
'order_create',
|
|
135
|
+
'order_cancel',
|
|
136
|
+
'stop_market_order_create',
|
|
137
|
+
'stop_market_order_cancel',
|
|
138
|
+
'user_open_orders',
|
|
139
|
+
'user_trades',
|
|
140
|
+
'user_cancelled_orders',
|
|
141
|
+
'order_trades',
|
|
142
|
+
'deposit_address',
|
|
143
|
+
'withdraw_crypt',
|
|
144
|
+
'withdraw_get_txid',
|
|
145
|
+
'excode_create',
|
|
146
|
+
'excode_load',
|
|
147
|
+
'code_check',
|
|
148
|
+
'wallet_history',
|
|
149
|
+
'wallet_operations',
|
|
150
|
+
'margin/user/order/create',
|
|
151
|
+
'margin/user/order/update',
|
|
152
|
+
'margin/user/order/cancel',
|
|
153
|
+
'margin/user/position/close',
|
|
154
|
+
'margin/user/position/margin_add',
|
|
155
|
+
'margin/user/position/margin_remove',
|
|
156
|
+
'margin/currency/list',
|
|
157
|
+
'margin/pair/list',
|
|
158
|
+
'margin/settings',
|
|
159
|
+
'margin/funding/list',
|
|
160
|
+
'margin/user/info',
|
|
161
|
+
'margin/user/order/list',
|
|
162
|
+
'margin/user/order/history',
|
|
163
|
+
'margin/user/order/trades',
|
|
164
|
+
'margin/user/order/max_quantity',
|
|
165
|
+
'margin/user/position/list',
|
|
166
|
+
'margin/user/position/margin_remove_info',
|
|
167
|
+
'margin/user/position/margin_add_info',
|
|
168
|
+
'margin/user/wallet/list',
|
|
169
|
+
'margin/user/wallet/history',
|
|
170
|
+
'margin/user/trade/list',
|
|
171
|
+
'margin/trades',
|
|
172
|
+
'margin/liquidation/feed',
|
|
173
|
+
],
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
'fees': {
|
|
177
|
+
'trading': {
|
|
178
|
+
'feeSide': 'get',
|
|
179
|
+
'tierBased': true,
|
|
180
|
+
'percentage': true,
|
|
181
|
+
'maker': this.parseNumber('0.004'),
|
|
182
|
+
'taker': this.parseNumber('0.004'),
|
|
183
|
+
},
|
|
184
|
+
'transaction': {
|
|
185
|
+
'tierBased': false,
|
|
186
|
+
'percentage': false, // fixed transaction fees for crypto, see fetchDepositWithdrawFees below
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
'options': {
|
|
190
|
+
'networks': {
|
|
191
|
+
'ETH': 'ERC20',
|
|
192
|
+
'TRX': 'TRC20',
|
|
193
|
+
},
|
|
194
|
+
'fetchTradingFees': {
|
|
195
|
+
'method': 'fetchPrivateTradingFees', // or 'fetchPublicTradingFees'
|
|
196
|
+
},
|
|
197
|
+
'margin': {
|
|
198
|
+
'fillResponseFromRequest': true,
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
'commonCurrencies': {
|
|
202
|
+
'GMT': 'GMT Token',
|
|
203
|
+
},
|
|
204
|
+
'precisionMode': number.TICK_SIZE,
|
|
205
|
+
'exceptions': {
|
|
206
|
+
'exact': {
|
|
207
|
+
'140434': errors.BadRequest,
|
|
208
|
+
'40005': errors.AuthenticationError,
|
|
209
|
+
'40009': errors.InvalidNonce,
|
|
210
|
+
'40015': errors.ExchangeError,
|
|
211
|
+
'40016': errors.OnMaintenance,
|
|
212
|
+
'40017': errors.AuthenticationError,
|
|
213
|
+
'40032': errors.PermissionDenied,
|
|
214
|
+
'40033': errors.PermissionDenied,
|
|
215
|
+
'40034': errors.RateLimitExceeded,
|
|
216
|
+
'50052': errors.InsufficientFunds,
|
|
217
|
+
'50054': errors.InsufficientFunds,
|
|
218
|
+
'50304': errors.OrderNotFound,
|
|
219
|
+
'50173': errors.OrderNotFound,
|
|
220
|
+
'50277': errors.InvalidOrder,
|
|
221
|
+
'50319': errors.InvalidOrder,
|
|
222
|
+
'50321': errors.InvalidOrder,
|
|
223
|
+
'50381': errors.InvalidOrder, // {"result":false,"error":"Error 50381: More than 2 decimal places are not permitted for pair BTC_USD"}
|
|
224
|
+
},
|
|
225
|
+
'broad': {
|
|
226
|
+
'range period is too long': errors.BadRequest,
|
|
227
|
+
'invalid syntax': errors.BadRequest,
|
|
228
|
+
'API rate limit exceeded': errors.RateLimitExceeded, // {"result":false,"error":"API rate limit exceeded for x.x.x.x. Retry after 60 sec.","history":[],"begin":1579392000,"end":1579478400}
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
async modifyMarginHelper(symbol, amount, type, params = {}) {
|
|
234
|
+
await this.loadMarkets();
|
|
235
|
+
const market = this.market(symbol);
|
|
236
|
+
const request = {
|
|
237
|
+
'position_id': market['id'],
|
|
238
|
+
'quantity': amount,
|
|
239
|
+
};
|
|
240
|
+
let response = undefined;
|
|
241
|
+
if (type === 'add') {
|
|
242
|
+
response = await this.privatePostMarginUserPositionMarginAdd(this.extend(request, params));
|
|
243
|
+
}
|
|
244
|
+
else if (type === 'reduce') {
|
|
245
|
+
response = await this.privatePostMarginUserPositionMarginRemove(this.extend(request, params));
|
|
246
|
+
}
|
|
247
|
+
//
|
|
248
|
+
// {}
|
|
249
|
+
//
|
|
250
|
+
const margin = this.parseMarginModification(response, market);
|
|
251
|
+
const options = this.safeValue(this.options, 'margin', {});
|
|
252
|
+
const fillResponseFromRequest = this.safeValue(options, 'fillResponseFromRequest', true);
|
|
253
|
+
if (fillResponseFromRequest) {
|
|
254
|
+
margin['type'] = type;
|
|
255
|
+
margin['amount'] = amount;
|
|
256
|
+
}
|
|
257
|
+
return margin;
|
|
258
|
+
}
|
|
259
|
+
parseMarginModification(data, market = undefined) {
|
|
260
|
+
//
|
|
261
|
+
// {}
|
|
262
|
+
//
|
|
263
|
+
return {
|
|
264
|
+
'info': data,
|
|
265
|
+
'type': undefined,
|
|
266
|
+
'amount': undefined,
|
|
267
|
+
'code': this.safeValue(market, 'quote'),
|
|
268
|
+
'symbol': this.safeSymbol(undefined, market),
|
|
269
|
+
'total': undefined,
|
|
270
|
+
'status': 'ok',
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
async reduceMargin(symbol, amount, params = {}) {
|
|
274
|
+
/**
|
|
275
|
+
* @method
|
|
276
|
+
* @name exmo#reduceMargin
|
|
277
|
+
* @description remove margin from a position
|
|
278
|
+
* @param {string} symbol unified market symbol
|
|
279
|
+
* @param {float} amount the amount of margin to remove
|
|
280
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
281
|
+
* @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=reduce-margin-structure}
|
|
282
|
+
*/
|
|
283
|
+
return await this.modifyMarginHelper(symbol, amount, 'reduce', params);
|
|
284
|
+
}
|
|
285
|
+
async addMargin(symbol, amount, params = {}) {
|
|
286
|
+
/**
|
|
287
|
+
* @method
|
|
288
|
+
* @name exmo#addMargin
|
|
289
|
+
* @description add margin
|
|
290
|
+
* @param {string} symbol unified market symbol
|
|
291
|
+
* @param {float} amount amount of margin to add
|
|
292
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
293
|
+
* @returns {object} a [margin structure]{@link https://docs.ccxt.com/#/?id=add-margin-structure}
|
|
294
|
+
*/
|
|
295
|
+
return await this.modifyMarginHelper(symbol, amount, 'add', params);
|
|
296
|
+
}
|
|
297
|
+
async fetchTradingFees(params = {}) {
|
|
298
|
+
/**
|
|
299
|
+
* @method
|
|
300
|
+
* @name exmo#fetchTradingFees
|
|
301
|
+
* @description fetch the trading fees for multiple markets
|
|
302
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
303
|
+
* @returns {object} a dictionary of [fee structures]{@link https://docs.ccxt.com/#/?id=fee-structure} indexed by market symbols
|
|
304
|
+
*/
|
|
305
|
+
const options = this.safeValue(this.options, 'fetchTradingFees', {});
|
|
306
|
+
const defaultMethod = this.safeString(options, 'method', 'fetchPrivateTradingFees');
|
|
307
|
+
const method = this.safeString(params, 'method', defaultMethod);
|
|
308
|
+
params = this.omit(params, 'method');
|
|
309
|
+
if (method === 'fetchPrivateTradingFees') {
|
|
310
|
+
return await this.fetchPrivateTradingFees(params);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
return await this.fetchPublicTradingFees(params);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
async fetchPrivateTradingFees(params = {}) {
|
|
317
|
+
await this.loadMarkets();
|
|
318
|
+
const response = await this.privatePostMarginPairList(params);
|
|
319
|
+
//
|
|
320
|
+
// {
|
|
321
|
+
// "pairs": [{
|
|
322
|
+
// "name": "EXM_USD",
|
|
323
|
+
// "buy_price": "0.02728391",
|
|
324
|
+
// "sell_price": "0.0276",
|
|
325
|
+
// "last_trade_price": "0.0276",
|
|
326
|
+
// "ticker_updated": "1646956050056696046",
|
|
327
|
+
// "is_fair_price": true,
|
|
328
|
+
// "max_price_precision": "8",
|
|
329
|
+
// "min_order_quantity": "1",
|
|
330
|
+
// "max_order_quantity": "50000",
|
|
331
|
+
// "min_order_price": "0.00000001",
|
|
332
|
+
// "max_order_price": "1000",
|
|
333
|
+
// "max_position_quantity": "50000",
|
|
334
|
+
// "trade_taker_fee": "0.05",
|
|
335
|
+
// "trade_maker_fee": "0",
|
|
336
|
+
// "liquidation_fee": "0.5",
|
|
337
|
+
// "max_leverage": "3",
|
|
338
|
+
// "default_leverage": "3",
|
|
339
|
+
// "liquidation_level": "5",
|
|
340
|
+
// "margin_call_level": "7.5",
|
|
341
|
+
// "position": "1",
|
|
342
|
+
// "updated": "1638976144797807397"
|
|
343
|
+
// }
|
|
344
|
+
// ...
|
|
345
|
+
// ]
|
|
346
|
+
// }
|
|
347
|
+
//
|
|
348
|
+
const pairs = this.safeValue(response, 'pairs', []);
|
|
349
|
+
const result = {};
|
|
350
|
+
for (let i = 0; i < pairs.length; i++) {
|
|
351
|
+
const pair = pairs[i];
|
|
352
|
+
const marketId = this.safeString(pair, 'name');
|
|
353
|
+
const symbol = this.safeSymbol(marketId, undefined, '_');
|
|
354
|
+
const makerString = this.safeString(pair, 'trade_maker_fee');
|
|
355
|
+
const takerString = this.safeString(pair, 'trade_taker_fee');
|
|
356
|
+
const maker = this.parseNumber(Precise["default"].stringDiv(makerString, '100'));
|
|
357
|
+
const taker = this.parseNumber(Precise["default"].stringDiv(takerString, '100'));
|
|
358
|
+
result[symbol] = {
|
|
359
|
+
'info': pair,
|
|
360
|
+
'symbol': symbol,
|
|
361
|
+
'maker': maker,
|
|
362
|
+
'taker': taker,
|
|
363
|
+
'percentage': true,
|
|
364
|
+
'tierBased': true,
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
return result;
|
|
368
|
+
}
|
|
369
|
+
async fetchPublicTradingFees(params = {}) {
|
|
370
|
+
await this.loadMarkets();
|
|
371
|
+
const response = await this.publicGetPairSettings(params);
|
|
372
|
+
//
|
|
373
|
+
// {
|
|
374
|
+
// "BTC_USD": {
|
|
375
|
+
// "min_quantity": "0.00002",
|
|
376
|
+
// "max_quantity": "1000",
|
|
377
|
+
// "min_price": "1",
|
|
378
|
+
// "max_price": "150000",
|
|
379
|
+
// "max_amount": "500000",
|
|
380
|
+
// "min_amount": "1",
|
|
381
|
+
// "price_precision": "2",
|
|
382
|
+
// "commission_taker_percent": "0.3",
|
|
383
|
+
// "commission_maker_percent": "0.3"
|
|
384
|
+
// },
|
|
385
|
+
// }
|
|
386
|
+
//
|
|
387
|
+
const result = {};
|
|
388
|
+
for (let i = 0; i < this.symbols.length; i++) {
|
|
389
|
+
const symbol = this.symbols[i];
|
|
390
|
+
const market = this.market(symbol);
|
|
391
|
+
const fee = this.safeValue(response, market['id'], {});
|
|
392
|
+
const makerString = this.safeString(fee, 'commission_maker_percent');
|
|
393
|
+
const takerString = this.safeString(fee, 'commission_taker_percent');
|
|
394
|
+
const maker = this.parseNumber(Precise["default"].stringDiv(makerString, '100'));
|
|
395
|
+
const taker = this.parseNumber(Precise["default"].stringDiv(takerString, '100'));
|
|
396
|
+
result[symbol] = {
|
|
397
|
+
'info': fee,
|
|
398
|
+
'symbol': symbol,
|
|
399
|
+
'maker': maker,
|
|
400
|
+
'taker': taker,
|
|
401
|
+
'percentage': true,
|
|
402
|
+
'tierBased': true,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
return result;
|
|
406
|
+
}
|
|
407
|
+
parseFixedFloatValue(input) {
|
|
408
|
+
if ((input === undefined) || (input === '-')) {
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
if (input === '') {
|
|
412
|
+
return 0;
|
|
413
|
+
}
|
|
414
|
+
const isPercentage = (input.indexOf('%') >= 0);
|
|
415
|
+
const parts = input.split(' ');
|
|
416
|
+
const value = parts[0].replace('%', '');
|
|
417
|
+
const result = parseFloat(value);
|
|
418
|
+
if ((result > 0) && isPercentage) {
|
|
419
|
+
throw new errors.ExchangeError(this.id + ' parseFixedFloatValue() detected an unsupported non-zero percentage-based fee ' + input);
|
|
420
|
+
}
|
|
421
|
+
return result;
|
|
422
|
+
}
|
|
423
|
+
async fetchTransactionFees(codes = undefined, params = {}) {
|
|
424
|
+
/**
|
|
425
|
+
* @method
|
|
426
|
+
* @name exmo#fetchTransactionFees
|
|
427
|
+
* @deprecated
|
|
428
|
+
* @description please use fetchDepositWithdrawFees instead
|
|
429
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#4190035d-24b1-453d-833b-37e0a52f88e2
|
|
430
|
+
* @param {string[]|undefined} codes list of unified currency codes
|
|
431
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
432
|
+
* @returns {object} a list of [transaction fees structures]{@link https://docs.ccxt.com/#/?id=fees-structure}
|
|
433
|
+
*/
|
|
434
|
+
await this.loadMarkets();
|
|
435
|
+
const cryptoList = await this.publicGetPaymentsProvidersCryptoList(params);
|
|
436
|
+
//
|
|
437
|
+
// {
|
|
438
|
+
// "BTC":[
|
|
439
|
+
// { "type":"deposit", "name":"BTC", "currency_name":"BTC", "min":"0.001", "max":"0", "enabled":true,"comment":"Minimum deposit amount is 0.001 BTC. We do not support BSC and BEP20 network, please consider this when sending funds", "commission_desc":"0%", "currency_confirmations":1 },
|
|
440
|
+
// { "type":"withdraw", "name":"BTC", "currency_name":"BTC", "min":"0.001", "max":"350", "enabled":true,"comment":"Do not withdraw directly to the Crowdfunding or ICO address as your account will not be credited with tokens from such sales.", "commission_desc":"0.0005 BTC", "currency_confirmations":6 }
|
|
441
|
+
// ],
|
|
442
|
+
// "ETH":[
|
|
443
|
+
// { "type":"withdraw", "name":"ETH", "currency_name":"ETH", "min":"0.01", "max":"500", "enabled":true,"comment":"Do not withdraw directly to the Crowdfunding or ICO address as your account will not be credited with tokens from such sales.", "commission_desc":"0.004 ETH", "currency_confirmations":4 },
|
|
444
|
+
// { "type":"deposit", "name":"ETH", "currency_name":"ETH", "min":"0.01", "max":"0", "enabled":true,"comment":"Minimum deposit amount is 0.01 ETH. We do not support BSC and BEP20 network, please consider this when sending funds", "commission_desc":"0%", "currency_confirmations":1 }
|
|
445
|
+
// ],
|
|
446
|
+
// "USDT":[
|
|
447
|
+
// { "type":"deposit", "name":"USDT (OMNI)", "currency_name":"USDT", "min":"10", "max":"0", "enabled":false,"comment":"Minimum deposit amount is 10 USDT", "commission_desc":"0%", "currency_confirmations":2 },
|
|
448
|
+
// { "type":"withdraw", "name":"USDT (OMNI)", "currency_name":"USDT", "min":"10", "max":"100000", "enabled":false,"comment":"Do not withdraw directly to the Crowdfunding or ICO address as your account will not be credited with tokens from such sales.", "commission_desc":"5 USDT", "currency_confirmations":6 },
|
|
449
|
+
// { "type":"deposit", "name":"USDT (ERC20)", "currency_name":"USDT", "min":"10", "max":"0", "enabled":true,"comment":"Minimum deposit amount is 10 USDT", "commission_desc":"0%", "currency_confirmations":2 },
|
|
450
|
+
// {
|
|
451
|
+
// "type":"withdraw",
|
|
452
|
+
// "name":"USDT (ERC20)",
|
|
453
|
+
// "currency_name":"USDT",
|
|
454
|
+
// "min":"55",
|
|
455
|
+
// "max":"200000",
|
|
456
|
+
// "enabled":true,
|
|
457
|
+
// "comment":"Caution! Do not withdraw directly to a crowdfund or ICO address, as your account will not be credited with tokens from such sales. Recommendation: Due to the high load of ERC20 network, using TRC20 address for withdrawal is recommended.",
|
|
458
|
+
// "commission_desc":"10 USDT",
|
|
459
|
+
// "currency_confirmations":6
|
|
460
|
+
// },
|
|
461
|
+
// { "type":"deposit", "name":"USDT (TRC20)", "currency_name":"USDT", "min":"10", "max":"100000", "enabled":true,"comment":"Minimum deposit amount is 10 USDT. Only TRON main network supported", "commission_desc":"0%", "currency_confirmations":2 },
|
|
462
|
+
// { "type":"withdraw", "name":"USDT (TRC20)", "currency_name":"USDT", "min":"10", "max":"150000", "enabled":true,"comment":"Caution! Do not withdraw directly to a crowdfund or ICO address, as your account will not be credited with tokens from such sales. Only TRON main network supported.", "commission_desc":"1 USDT", "currency_confirmations":6 }
|
|
463
|
+
// ],
|
|
464
|
+
// "XLM":[
|
|
465
|
+
// { "type":"deposit", "name":"XLM", "currency_name":"XLM", "min":"1", "max":"1000000", "enabled":true,"comment":"Attention! A deposit without memo(invoice) will not be credited. Minimum deposit amount is 1 XLM. We do not support BSC and BEP20 network, please consider this when sending funds", "commission_desc":"0%", "currency_confirmations":1 },
|
|
466
|
+
// { "type":"withdraw", "name":"XLM", "currency_name":"XLM", "min":"21", "max":"1000000", "enabled":true,"comment":"Caution! Do not withdraw directly to a crowdfund or ICO address, as your account will not be credited with tokens from such sales.", "commission_desc":"0.01 XLM", "currency_confirmations":1 }
|
|
467
|
+
// ],
|
|
468
|
+
// }
|
|
469
|
+
//
|
|
470
|
+
const result = {};
|
|
471
|
+
const cryptoListKeys = Object.keys(cryptoList);
|
|
472
|
+
for (let i = 0; i < cryptoListKeys.length; i++) {
|
|
473
|
+
const code = cryptoListKeys[i];
|
|
474
|
+
if (codes !== undefined && !this.inArray(code, codes)) {
|
|
475
|
+
continue;
|
|
476
|
+
}
|
|
477
|
+
result[code] = {
|
|
478
|
+
'deposit': undefined,
|
|
479
|
+
'withdraw': undefined,
|
|
480
|
+
};
|
|
481
|
+
const currency = this.currency(code);
|
|
482
|
+
const currencyId = this.safeString(currency, 'id');
|
|
483
|
+
const providers = this.safeValue(cryptoList, currencyId, []);
|
|
484
|
+
for (let j = 0; j < providers.length; j++) {
|
|
485
|
+
const provider = providers[j];
|
|
486
|
+
const typeInner = this.safeString(provider, 'type');
|
|
487
|
+
const commissionDesc = this.safeString(provider, 'commission_desc');
|
|
488
|
+
const fee = this.parseFixedFloatValue(commissionDesc);
|
|
489
|
+
result[code][typeInner] = fee;
|
|
490
|
+
}
|
|
491
|
+
result[code]['info'] = providers;
|
|
492
|
+
}
|
|
493
|
+
// cache them for later use
|
|
494
|
+
this.options['transactionFees'] = result;
|
|
495
|
+
return result;
|
|
496
|
+
}
|
|
497
|
+
async fetchDepositWithdrawFees(codes = undefined, params = {}) {
|
|
498
|
+
/**
|
|
499
|
+
* @method
|
|
500
|
+
* @name exmo#fetchDepositWithdrawFees
|
|
501
|
+
* @description fetch deposit and withdraw fees
|
|
502
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#4190035d-24b1-453d-833b-37e0a52f88e2
|
|
503
|
+
* @param {string[]|undefined} codes list of unified currency codes
|
|
504
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
505
|
+
* @returns {object} a list of [transaction fees structures]{@link https://docs.ccxt.com/#/?id=fees-structure}
|
|
506
|
+
*/
|
|
507
|
+
await this.loadMarkets();
|
|
508
|
+
const response = await this.publicGetPaymentsProvidersCryptoList(params);
|
|
509
|
+
//
|
|
510
|
+
// {
|
|
511
|
+
// "USDT": [
|
|
512
|
+
// {
|
|
513
|
+
// "type": "deposit", // or "withdraw"
|
|
514
|
+
// "name": "USDT (ERC20)",
|
|
515
|
+
// "currency_name": "USDT",
|
|
516
|
+
// "min": "10",
|
|
517
|
+
// "max": "0",
|
|
518
|
+
// "enabled": true,
|
|
519
|
+
// "comment": "Minimum deposit amount is 10 USDT",
|
|
520
|
+
// "commission_desc": "0%",
|
|
521
|
+
// "currency_confirmations": 2
|
|
522
|
+
// },
|
|
523
|
+
// ...
|
|
524
|
+
// ],
|
|
525
|
+
// ...
|
|
526
|
+
// }
|
|
527
|
+
//
|
|
528
|
+
const result = this.parseDepositWithdrawFees(response, codes);
|
|
529
|
+
// cache them for later use
|
|
530
|
+
this.options['transactionFees'] = result;
|
|
531
|
+
return result;
|
|
532
|
+
}
|
|
533
|
+
parseDepositWithdrawFee(fee, currency = undefined) {
|
|
534
|
+
//
|
|
535
|
+
// [
|
|
536
|
+
// {
|
|
537
|
+
// "type": "deposit", // or "withdraw"
|
|
538
|
+
// "name": "BTC",
|
|
539
|
+
// "currency_name": "BTC",
|
|
540
|
+
// "min": "0.001",
|
|
541
|
+
// "max": "0",
|
|
542
|
+
// "enabled": true,
|
|
543
|
+
// "comment": "Minimum deposit amount is 0.001 BTC. We do not support BSC and BEP20 network, please consider this when sending funds",
|
|
544
|
+
// "commission_desc": "0%",
|
|
545
|
+
// "currency_confirmations": 1
|
|
546
|
+
// },
|
|
547
|
+
// ...
|
|
548
|
+
// ]
|
|
549
|
+
//
|
|
550
|
+
const result = this.depositWithdrawFee(fee);
|
|
551
|
+
for (let i = 0; i < fee.length; i++) {
|
|
552
|
+
const provider = fee[i];
|
|
553
|
+
const type = this.safeString(provider, 'type');
|
|
554
|
+
const networkId = this.safeString(provider, 'name');
|
|
555
|
+
const networkCode = this.networkIdToCode(networkId, this.safeString(currency, 'code'));
|
|
556
|
+
const commissionDesc = this.safeString(provider, 'commission_desc');
|
|
557
|
+
let splitCommissionDesc = [];
|
|
558
|
+
let percentage = undefined;
|
|
559
|
+
if (commissionDesc !== undefined) {
|
|
560
|
+
splitCommissionDesc = commissionDesc.split('%');
|
|
561
|
+
const splitCommissionDescLength = splitCommissionDesc.length;
|
|
562
|
+
percentage = splitCommissionDescLength >= 2;
|
|
563
|
+
}
|
|
564
|
+
const network = this.safeValue(result['networks'], networkCode);
|
|
565
|
+
if (network === undefined) {
|
|
566
|
+
result['networks'][networkCode] = {
|
|
567
|
+
'withdraw': {
|
|
568
|
+
'fee': undefined,
|
|
569
|
+
'percentage': undefined,
|
|
570
|
+
},
|
|
571
|
+
'deposit': {
|
|
572
|
+
'fee': undefined,
|
|
573
|
+
'percentage': undefined,
|
|
574
|
+
},
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
result['networks'][networkCode][type] = {
|
|
578
|
+
'fee': this.parseFixedFloatValue(this.safeString(splitCommissionDesc, 0)),
|
|
579
|
+
'percentage': percentage,
|
|
580
|
+
};
|
|
581
|
+
}
|
|
582
|
+
return this.assignDefaultDepositWithdrawFees(result);
|
|
583
|
+
}
|
|
584
|
+
async fetchCurrencies(params = {}) {
|
|
585
|
+
/**
|
|
586
|
+
* @method
|
|
587
|
+
* @name exmo#fetchCurrencies
|
|
588
|
+
* @description fetches all available currencies on an exchange
|
|
589
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
590
|
+
* @returns {object} an associative dictionary of currencies
|
|
591
|
+
*/
|
|
592
|
+
//
|
|
593
|
+
const currencyList = await this.publicGetCurrencyListExtended(params);
|
|
594
|
+
//
|
|
595
|
+
// [
|
|
596
|
+
// {"name":"VLX","description":"Velas"},
|
|
597
|
+
// {"name":"RUB","description":"Russian Ruble"},
|
|
598
|
+
// {"name":"BTC","description":"Bitcoin"},
|
|
599
|
+
// {"name":"USD","description":"US Dollar"}
|
|
600
|
+
// ]
|
|
601
|
+
//
|
|
602
|
+
const cryptoList = await this.publicGetPaymentsProvidersCryptoList(params);
|
|
603
|
+
//
|
|
604
|
+
// {
|
|
605
|
+
// "BTC":[
|
|
606
|
+
// { "type":"deposit", "name":"BTC", "currency_name":"BTC", "min":"0.001", "max":"0", "enabled":true,"comment":"Minimum deposit amount is 0.001 BTC. We do not support BSC and BEP20 network, please consider this when sending funds", "commission_desc":"0%", "currency_confirmations":1 },
|
|
607
|
+
// { "type":"withdraw", "name":"BTC", "currency_name":"BTC", "min":"0.001", "max":"350", "enabled":true,"comment":"Do not withdraw directly to the Crowdfunding or ICO address as your account will not be credited with tokens from such sales.", "commission_desc":"0.0005 BTC", "currency_confirmations":6 }
|
|
608
|
+
// ],
|
|
609
|
+
// "ETH":[
|
|
610
|
+
// { "type":"withdraw", "name":"ETH", "currency_name":"ETH", "min":"0.01", "max":"500", "enabled":true,"comment":"Do not withdraw directly to the Crowdfunding or ICO address as your account will not be credited with tokens from such sales.", "commission_desc":"0.004 ETH", "currency_confirmations":4 },
|
|
611
|
+
// { "type":"deposit", "name":"ETH", "currency_name":"ETH", "min":"0.01", "max":"0", "enabled":true,"comment":"Minimum deposit amount is 0.01 ETH. We do not support BSC and BEP20 network, please consider this when sending funds", "commission_desc":"0%", "currency_confirmations":1 }
|
|
612
|
+
// ],
|
|
613
|
+
// "USDT":[
|
|
614
|
+
// { "type":"deposit", "name":"USDT (OMNI)", "currency_name":"USDT", "min":"10", "max":"0", "enabled":false,"comment":"Minimum deposit amount is 10 USDT", "commission_desc":"0%", "currency_confirmations":2 },
|
|
615
|
+
// { "type":"withdraw", "name":"USDT (OMNI)", "currency_name":"USDT", "min":"10", "max":"100000", "enabled":false,"comment":"Do not withdraw directly to the Crowdfunding or ICO address as your account will not be credited with tokens from such sales.", "commission_desc":"5 USDT", "currency_confirmations":6 },
|
|
616
|
+
// { "type":"deposit", "name":"USDT (ERC20)", "currency_name":"USDT", "min":"10", "max":"0", "enabled":true,"comment":"Minimum deposit amount is 10 USDT", "commission_desc":"0%", "currency_confirmations":2 },
|
|
617
|
+
// { "type":"withdraw", "name":"USDT (ERC20)", "currency_name":"USDT", "min":"55", "max":"200000", "enabled":true, "comment":"Caution! Do not withdraw directly to a crowdfund or ICO address, as your account will not be credited with tokens from such sales. Recommendation: Due to the high load of ERC20 network, using TRC20 address for withdrawal is recommended.", "commission_desc":"10 USDT", "currency_confirmations":6 },
|
|
618
|
+
// { "type":"deposit", "name":"USDT (TRC20)", "currency_name":"USDT", "min":"10", "max":"100000", "enabled":true,"comment":"Minimum deposit amount is 10 USDT. Only TRON main network supported", "commission_desc":"0%", "currency_confirmations":2 },
|
|
619
|
+
// { "type":"withdraw", "name":"USDT (TRC20)", "currency_name":"USDT", "min":"10", "max":"150000", "enabled":true,"comment":"Caution! Do not withdraw directly to a crowdfund or ICO address, as your account will not be credited with tokens from such sales. Only TRON main network supported.", "commission_desc":"1 USDT", "currency_confirmations":6 }
|
|
620
|
+
// ],
|
|
621
|
+
// "XLM":[
|
|
622
|
+
// { "type":"deposit", "name":"XLM", "currency_name":"XLM", "min":"1", "max":"1000000", "enabled":true,"comment":"Attention! A deposit without memo(invoice) will not be credited. Minimum deposit amount is 1 XLM. We do not support BSC and BEP20 network, please consider this when sending funds", "commission_desc":"0%", "currency_confirmations":1 },
|
|
623
|
+
// { "type":"withdraw", "name":"XLM", "currency_name":"XLM", "min":"21", "max":"1000000", "enabled":true,"comment":"Caution! Do not withdraw directly to a crowdfund or ICO address, as your account will not be credited with tokens from such sales.", "commission_desc":"0.01 XLM", "currency_confirmations":1 }
|
|
624
|
+
// ],
|
|
625
|
+
// }
|
|
626
|
+
//
|
|
627
|
+
const result = {};
|
|
628
|
+
for (let i = 0; i < currencyList.length; i++) {
|
|
629
|
+
const currency = currencyList[i];
|
|
630
|
+
const currencyId = this.safeString(currency, 'name');
|
|
631
|
+
const name = this.safeString(currency, 'description');
|
|
632
|
+
const providers = this.safeValue(cryptoList, currencyId);
|
|
633
|
+
let active = false;
|
|
634
|
+
let type = 'crypto';
|
|
635
|
+
const limits = {
|
|
636
|
+
'deposit': {
|
|
637
|
+
'min': undefined,
|
|
638
|
+
'max': undefined,
|
|
639
|
+
},
|
|
640
|
+
'withdraw': {
|
|
641
|
+
'min': undefined,
|
|
642
|
+
'max': undefined,
|
|
643
|
+
},
|
|
644
|
+
};
|
|
645
|
+
let fee = undefined;
|
|
646
|
+
let depositEnabled = undefined;
|
|
647
|
+
let withdrawEnabled = undefined;
|
|
648
|
+
if (providers === undefined) {
|
|
649
|
+
active = true;
|
|
650
|
+
type = 'fiat';
|
|
651
|
+
}
|
|
652
|
+
else {
|
|
653
|
+
for (let j = 0; j < providers.length; j++) {
|
|
654
|
+
const provider = providers[j];
|
|
655
|
+
const typeInner = this.safeString(provider, 'type');
|
|
656
|
+
const minValue = this.safeString(provider, 'min');
|
|
657
|
+
let maxValue = this.safeString(provider, 'max');
|
|
658
|
+
if (Precise["default"].stringEq(maxValue, '0.0')) {
|
|
659
|
+
maxValue = undefined;
|
|
660
|
+
}
|
|
661
|
+
const activeProvider = this.safeValue(provider, 'enabled');
|
|
662
|
+
if (typeInner === 'deposit') {
|
|
663
|
+
if (activeProvider && !depositEnabled) {
|
|
664
|
+
depositEnabled = true;
|
|
665
|
+
}
|
|
666
|
+
else if (!activeProvider) {
|
|
667
|
+
depositEnabled = false;
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
else if (typeInner === 'withdraw') {
|
|
671
|
+
if (activeProvider && !withdrawEnabled) {
|
|
672
|
+
withdrawEnabled = true;
|
|
673
|
+
}
|
|
674
|
+
else if (!activeProvider) {
|
|
675
|
+
withdrawEnabled = false;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
if (activeProvider) {
|
|
679
|
+
active = true;
|
|
680
|
+
const limitMin = this.numberToString(limits[typeInner]['min']);
|
|
681
|
+
if ((limits[typeInner]['min'] === undefined) || (Precise["default"].stringLt(minValue, limitMin))) {
|
|
682
|
+
limits[typeInner]['min'] = minValue;
|
|
683
|
+
limits[typeInner]['max'] = maxValue;
|
|
684
|
+
if (typeInner === 'withdraw') {
|
|
685
|
+
const commissionDesc = this.safeString(provider, 'commission_desc');
|
|
686
|
+
fee = this.parseFixedFloatValue(commissionDesc);
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
const code = this.safeCurrencyCode(currencyId);
|
|
693
|
+
result[code] = {
|
|
694
|
+
'id': currencyId,
|
|
695
|
+
'code': code,
|
|
696
|
+
'name': name,
|
|
697
|
+
'type': type,
|
|
698
|
+
'active': active,
|
|
699
|
+
'deposit': depositEnabled,
|
|
700
|
+
'withdraw': withdrawEnabled,
|
|
701
|
+
'fee': fee,
|
|
702
|
+
'precision': this.parseNumber('1e-8'),
|
|
703
|
+
'limits': limits,
|
|
704
|
+
'info': providers,
|
|
705
|
+
'networks': {},
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
return result;
|
|
709
|
+
}
|
|
710
|
+
async fetchMarkets(params = {}) {
|
|
711
|
+
/**
|
|
712
|
+
* @method
|
|
713
|
+
* @name exmo#fetchMarkets
|
|
714
|
+
* @description retrieves data on all markets for exmo
|
|
715
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
716
|
+
* @returns {object[]} an array of objects representing market data
|
|
717
|
+
*/
|
|
718
|
+
const response = await this.publicGetPairSettings(params);
|
|
719
|
+
//
|
|
720
|
+
// {
|
|
721
|
+
// "BTC_USD":{
|
|
722
|
+
// "min_quantity":"0.0001",
|
|
723
|
+
// "max_quantity":"1000",
|
|
724
|
+
// "min_price":"1",
|
|
725
|
+
// "max_price":"30000",
|
|
726
|
+
// "max_amount":"500000",
|
|
727
|
+
// "min_amount":"1",
|
|
728
|
+
// "price_precision":8,
|
|
729
|
+
// "commission_taker_percent":"0.4",
|
|
730
|
+
// "commission_maker_percent":"0.4"
|
|
731
|
+
// },
|
|
732
|
+
// }
|
|
733
|
+
//
|
|
734
|
+
let marginPairsDict = {};
|
|
735
|
+
if (this.checkRequiredCredentials(false)) {
|
|
736
|
+
const marginPairs = await this.privatePostMarginPairList(params);
|
|
737
|
+
//
|
|
738
|
+
// {
|
|
739
|
+
// "pairs": [
|
|
740
|
+
// {
|
|
741
|
+
// "buy_price": "55978.85",
|
|
742
|
+
// "default_leverage": "3",
|
|
743
|
+
// "is_fair_price": true,
|
|
744
|
+
// "last_trade_price": "55999.23",
|
|
745
|
+
// "liquidation_fee": "2",
|
|
746
|
+
// "liquidation_level": "10",
|
|
747
|
+
// "margin_call_level": "15",
|
|
748
|
+
// "max_leverage": "3",
|
|
749
|
+
// "max_order_price": "150000",
|
|
750
|
+
// "max_order_quantity": "1",
|
|
751
|
+
// "max_position_quantity": "1",
|
|
752
|
+
// "max_price_precision": 2,
|
|
753
|
+
// "min_order_price": "1",
|
|
754
|
+
// "min_order_quantity": "0.00002",
|
|
755
|
+
// "name": "BTC_USD",
|
|
756
|
+
// "position": 1,
|
|
757
|
+
// "sell_price": "55985.51",
|
|
758
|
+
// "ticker_updated": "1619019818936107989",
|
|
759
|
+
// "trade_maker_fee": "0",
|
|
760
|
+
// "trade_taker_fee": "0.05",
|
|
761
|
+
// "updated": "1619008608955599013"
|
|
762
|
+
// }
|
|
763
|
+
// ]
|
|
764
|
+
// }
|
|
765
|
+
//
|
|
766
|
+
const pairs = this.safeValue(marginPairs, 'pairs');
|
|
767
|
+
marginPairsDict = this.indexBy(pairs, 'name');
|
|
768
|
+
}
|
|
769
|
+
const keys = Object.keys(response);
|
|
770
|
+
const result = [];
|
|
771
|
+
for (let i = 0; i < keys.length; i++) {
|
|
772
|
+
const id = keys[i];
|
|
773
|
+
const market = response[id];
|
|
774
|
+
const marginMarket = this.safeValue(marginPairsDict, id);
|
|
775
|
+
const symbol = id.replace('_', '/');
|
|
776
|
+
const [baseId, quoteId] = symbol.split('/');
|
|
777
|
+
const base = this.safeCurrencyCode(baseId);
|
|
778
|
+
const quote = this.safeCurrencyCode(quoteId);
|
|
779
|
+
const takerString = this.safeString(market, 'commission_taker_percent');
|
|
780
|
+
const makerString = this.safeString(market, 'commission_maker_percent');
|
|
781
|
+
const maxQuantity = this.safeString(market, 'max_quantity');
|
|
782
|
+
const marginMaxQuantity = this.safeString(marginMarket, 'max_order_quantity');
|
|
783
|
+
result.push({
|
|
784
|
+
'id': id,
|
|
785
|
+
'symbol': symbol,
|
|
786
|
+
'base': base,
|
|
787
|
+
'quote': quote,
|
|
788
|
+
'settle': undefined,
|
|
789
|
+
'baseId': baseId,
|
|
790
|
+
'quoteId': quoteId,
|
|
791
|
+
'settleId': undefined,
|
|
792
|
+
'type': 'spot',
|
|
793
|
+
'spot': true,
|
|
794
|
+
'margin': marginMarket !== undefined,
|
|
795
|
+
'swap': false,
|
|
796
|
+
'future': false,
|
|
797
|
+
'option': false,
|
|
798
|
+
'active': undefined,
|
|
799
|
+
'contract': false,
|
|
800
|
+
'linear': undefined,
|
|
801
|
+
'inverse': undefined,
|
|
802
|
+
'taker': this.parseNumber(Precise["default"].stringDiv(takerString, '100')),
|
|
803
|
+
'maker': this.parseNumber(Precise["default"].stringDiv(makerString, '100')),
|
|
804
|
+
'contractSize': undefined,
|
|
805
|
+
'expiry': undefined,
|
|
806
|
+
'expiryDatetime': undefined,
|
|
807
|
+
'strike': undefined,
|
|
808
|
+
'optionType': undefined,
|
|
809
|
+
'precision': {
|
|
810
|
+
'amount': this.parseNumber('1e-8'),
|
|
811
|
+
'price': this.parseNumber(this.parsePrecision(this.safeString(market, 'price_precision'))),
|
|
812
|
+
},
|
|
813
|
+
'limits': {
|
|
814
|
+
'leverage': {
|
|
815
|
+
'min': undefined,
|
|
816
|
+
'max': this.safeNumber(market, 'leverage'),
|
|
817
|
+
},
|
|
818
|
+
'amount': {
|
|
819
|
+
'min': this.safeNumber(market, 'min_quantity'),
|
|
820
|
+
'max': this.parseNumber(Precise["default"].stringMax(maxQuantity, marginMaxQuantity)),
|
|
821
|
+
},
|
|
822
|
+
'price': {
|
|
823
|
+
'min': this.safeNumber(market, 'min_price'),
|
|
824
|
+
'max': this.safeNumber(market, 'max_price'),
|
|
825
|
+
},
|
|
826
|
+
'cost': {
|
|
827
|
+
'min': this.safeNumber(market, 'min_amount'),
|
|
828
|
+
'max': this.safeNumber(market, 'max_amount'),
|
|
829
|
+
},
|
|
830
|
+
},
|
|
831
|
+
'created': undefined,
|
|
832
|
+
'info': market,
|
|
833
|
+
});
|
|
834
|
+
}
|
|
835
|
+
return result;
|
|
836
|
+
}
|
|
837
|
+
async fetchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
838
|
+
/**
|
|
839
|
+
* @method
|
|
840
|
+
* @name exmo#fetchOHLCV
|
|
841
|
+
* @description fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
842
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
843
|
+
* @param {string} timeframe the length of time each candle represents
|
|
844
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
845
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
846
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
847
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
848
|
+
*/
|
|
849
|
+
await this.loadMarkets();
|
|
850
|
+
const market = this.market(symbol);
|
|
851
|
+
const request = {
|
|
852
|
+
'symbol': market['id'],
|
|
853
|
+
'resolution': this.safeString(this.timeframes, timeframe, timeframe),
|
|
854
|
+
};
|
|
855
|
+
const options = this.safeValue(this.options, 'fetchOHLCV');
|
|
856
|
+
const maxLimit = this.safeInteger(options, 'maxLimit', 3000);
|
|
857
|
+
const duration = this.parseTimeframe(timeframe);
|
|
858
|
+
const now = this.milliseconds();
|
|
859
|
+
if (since === undefined) {
|
|
860
|
+
if (limit === undefined) {
|
|
861
|
+
limit = 1000; // cap default at generous amount
|
|
862
|
+
}
|
|
863
|
+
if (limit > maxLimit) {
|
|
864
|
+
limit = maxLimit; // avoid exception
|
|
865
|
+
}
|
|
866
|
+
request['from'] = this.parseToInt(now / 1000) - limit * duration - 1;
|
|
867
|
+
request['to'] = this.parseToInt(now / 1000);
|
|
868
|
+
}
|
|
869
|
+
else {
|
|
870
|
+
request['from'] = this.parseToInt(since / 1000) - 1;
|
|
871
|
+
if (limit === undefined) {
|
|
872
|
+
request['to'] = this.parseToInt(now / 1000);
|
|
873
|
+
}
|
|
874
|
+
else {
|
|
875
|
+
if (limit > maxLimit) {
|
|
876
|
+
throw new errors.BadRequest(this.id + ' fetchOHLCV() will serve ' + maxLimit.toString() + ' candles at most');
|
|
877
|
+
}
|
|
878
|
+
const to = this.sum(since, limit * duration * 1000);
|
|
879
|
+
request['to'] = this.parseToInt(to / 1000);
|
|
880
|
+
}
|
|
881
|
+
}
|
|
882
|
+
const response = await this.publicGetCandlesHistory(this.extend(request, params));
|
|
883
|
+
//
|
|
884
|
+
// {
|
|
885
|
+
// "candles":[
|
|
886
|
+
// {"t":1584057600000,"o":0.02235144,"c":0.02400233,"h":0.025171,"l":0.02221,"v":5988.34031761},
|
|
887
|
+
// {"t":1584144000000,"o":0.0240373,"c":0.02367413,"h":0.024399,"l":0.0235,"v":2027.82522329},
|
|
888
|
+
// {"t":1584230400000,"o":0.02363458,"c":0.02319242,"h":0.0237948,"l":0.02223196,"v":1707.96944997},
|
|
889
|
+
// ]
|
|
890
|
+
// }
|
|
891
|
+
//
|
|
892
|
+
const candles = this.safeValue(response, 'candles', []);
|
|
893
|
+
return this.parseOHLCVs(candles, market, timeframe, since, limit);
|
|
894
|
+
}
|
|
895
|
+
parseOHLCV(ohlcv, market = undefined) {
|
|
896
|
+
//
|
|
897
|
+
// {
|
|
898
|
+
// "t":1584057600000,
|
|
899
|
+
// "o":0.02235144,
|
|
900
|
+
// "c":0.02400233,
|
|
901
|
+
// "h":0.025171,
|
|
902
|
+
// "l":0.02221,
|
|
903
|
+
// "v":5988.34031761
|
|
904
|
+
// }
|
|
905
|
+
//
|
|
906
|
+
return [
|
|
907
|
+
this.safeInteger(ohlcv, 't'),
|
|
908
|
+
this.safeNumber(ohlcv, 'o'),
|
|
909
|
+
this.safeNumber(ohlcv, 'h'),
|
|
910
|
+
this.safeNumber(ohlcv, 'l'),
|
|
911
|
+
this.safeNumber(ohlcv, 'c'),
|
|
912
|
+
this.safeNumber(ohlcv, 'v'),
|
|
913
|
+
];
|
|
914
|
+
}
|
|
915
|
+
parseBalance(response) {
|
|
916
|
+
const result = { 'info': response };
|
|
917
|
+
const wallets = this.safeValue(response, 'wallets');
|
|
918
|
+
if (wallets !== undefined) {
|
|
919
|
+
const currencyIds = Object.keys(wallets);
|
|
920
|
+
for (let i = 0; i < currencyIds.length; i++) {
|
|
921
|
+
const currencyId = currencyIds[i];
|
|
922
|
+
const item = wallets[currencyId];
|
|
923
|
+
const currency = this.safeCurrencyCode(currencyId);
|
|
924
|
+
const account = this.account();
|
|
925
|
+
account['used'] = this.safeString(item, 'used');
|
|
926
|
+
account['free'] = this.safeString(item, 'free');
|
|
927
|
+
account['total'] = this.safeString(item, 'balance');
|
|
928
|
+
result[currency] = account;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
else {
|
|
932
|
+
const free = this.safeValue(response, 'balances', {});
|
|
933
|
+
const used = this.safeValue(response, 'reserved', {});
|
|
934
|
+
const currencyIds = Object.keys(free);
|
|
935
|
+
for (let i = 0; i < currencyIds.length; i++) {
|
|
936
|
+
const currencyId = currencyIds[i];
|
|
937
|
+
const code = this.safeCurrencyCode(currencyId);
|
|
938
|
+
const account = this.account();
|
|
939
|
+
if (currencyId in free) {
|
|
940
|
+
account['free'] = this.safeString(free, currencyId);
|
|
941
|
+
}
|
|
942
|
+
if (currencyId in used) {
|
|
943
|
+
account['used'] = this.safeString(used, currencyId);
|
|
944
|
+
}
|
|
945
|
+
result[code] = account;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
return this.safeBalance(result);
|
|
949
|
+
}
|
|
950
|
+
async fetchBalance(params = {}) {
|
|
951
|
+
/**
|
|
952
|
+
* @method
|
|
953
|
+
* @name exmo#fetchBalance
|
|
954
|
+
* @description query for balance and get the amount of funds available for trading or funds locked in orders
|
|
955
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
956
|
+
* @param {string} [params.marginMode] *isolated* fetches the isolated margin balance
|
|
957
|
+
* @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
|
|
958
|
+
*/
|
|
959
|
+
await this.loadMarkets();
|
|
960
|
+
let marginMode = undefined;
|
|
961
|
+
[marginMode, params] = this.handleMarginModeAndParams('fetchBalance', params);
|
|
962
|
+
if (marginMode === 'cross') {
|
|
963
|
+
throw new errors.BadRequest(this.id + ' does not support cross margin');
|
|
964
|
+
}
|
|
965
|
+
let response = undefined;
|
|
966
|
+
if (marginMode === 'isolated') {
|
|
967
|
+
response = await this.privatePostMarginUserWalletList(params);
|
|
968
|
+
//
|
|
969
|
+
// {
|
|
970
|
+
// "wallets": {
|
|
971
|
+
// "USD": {
|
|
972
|
+
// "balance": "1000",
|
|
973
|
+
// "free": "600",
|
|
974
|
+
// "used": "400"
|
|
975
|
+
// }
|
|
976
|
+
// }
|
|
977
|
+
// }
|
|
978
|
+
//
|
|
979
|
+
}
|
|
980
|
+
else {
|
|
981
|
+
response = await this.privatePostUserInfo(params);
|
|
982
|
+
//
|
|
983
|
+
// {
|
|
984
|
+
// "uid":131685,
|
|
985
|
+
// "server_date":1628999600,
|
|
986
|
+
// "balances":{
|
|
987
|
+
// "EXM":"0",
|
|
988
|
+
// "USD":"0",
|
|
989
|
+
// "EUR":"0",
|
|
990
|
+
// "GBP":"0",
|
|
991
|
+
// },
|
|
992
|
+
// }
|
|
993
|
+
//
|
|
994
|
+
}
|
|
995
|
+
return this.parseBalance(response);
|
|
996
|
+
}
|
|
997
|
+
async fetchOrderBook(symbol, limit = undefined, params = {}) {
|
|
998
|
+
/**
|
|
999
|
+
* @method
|
|
1000
|
+
* @name exmo#fetchOrderBook
|
|
1001
|
+
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
1002
|
+
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
1003
|
+
* @param {int} [limit] the maximum amount of order book entries to return
|
|
1004
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1005
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
1006
|
+
*/
|
|
1007
|
+
await this.loadMarkets();
|
|
1008
|
+
const market = this.market(symbol);
|
|
1009
|
+
const request = {
|
|
1010
|
+
'pair': market['id'],
|
|
1011
|
+
};
|
|
1012
|
+
if (limit !== undefined) {
|
|
1013
|
+
request['limit'] = limit;
|
|
1014
|
+
}
|
|
1015
|
+
const response = await this.publicGetOrderBook(this.extend(request, params));
|
|
1016
|
+
const result = this.safeValue(response, market['id']);
|
|
1017
|
+
return this.parseOrderBook(result, market['symbol'], undefined, 'bid', 'ask');
|
|
1018
|
+
}
|
|
1019
|
+
async fetchOrderBooks(symbols = undefined, limit = undefined, params = {}) {
|
|
1020
|
+
/**
|
|
1021
|
+
* @method
|
|
1022
|
+
* @name exmo#fetchOrderBooks
|
|
1023
|
+
* @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data for multiple markets
|
|
1024
|
+
* @param {string[]|undefined} symbols list of unified market symbols, all symbols fetched if undefined, default is undefined
|
|
1025
|
+
* @param {int} [limit] max number of entries per orderbook to return, default is undefined
|
|
1026
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1027
|
+
* @returns {object} a dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbol
|
|
1028
|
+
*/
|
|
1029
|
+
await this.loadMarkets();
|
|
1030
|
+
let ids = undefined;
|
|
1031
|
+
if (symbols === undefined) {
|
|
1032
|
+
ids = this.ids.join(',');
|
|
1033
|
+
// max URL length is 2083 symbols, including http schema, hostname, tld, etc...
|
|
1034
|
+
if (ids.length > 2048) {
|
|
1035
|
+
const numIds = this.ids.length;
|
|
1036
|
+
throw new errors.ExchangeError(this.id + ' fetchOrderBooks() has ' + numIds.toString() + ' symbols exceeding max URL length, you are required to specify a list of symbols in the first argument to fetchOrderBooks');
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
else {
|
|
1040
|
+
ids = this.marketIds(symbols);
|
|
1041
|
+
ids = ids.join(',');
|
|
1042
|
+
}
|
|
1043
|
+
const request = {
|
|
1044
|
+
'pair': ids,
|
|
1045
|
+
};
|
|
1046
|
+
if (limit !== undefined) {
|
|
1047
|
+
request['limit'] = limit;
|
|
1048
|
+
}
|
|
1049
|
+
const response = await this.publicGetOrderBook(this.extend(request, params));
|
|
1050
|
+
const result = {};
|
|
1051
|
+
const marketIds = Object.keys(response);
|
|
1052
|
+
for (let i = 0; i < marketIds.length; i++) {
|
|
1053
|
+
const marketId = marketIds[i];
|
|
1054
|
+
const symbol = this.safeSymbol(marketId);
|
|
1055
|
+
result[symbol] = this.parseOrderBook(response[marketId], symbol, undefined, 'bid', 'ask');
|
|
1056
|
+
}
|
|
1057
|
+
return result;
|
|
1058
|
+
}
|
|
1059
|
+
parseTicker(ticker, market = undefined) {
|
|
1060
|
+
//
|
|
1061
|
+
// {
|
|
1062
|
+
// "buy_price":"0.00002996",
|
|
1063
|
+
// "sell_price":"0.00003002",
|
|
1064
|
+
// "last_trade":"0.00002992",
|
|
1065
|
+
// "high":"0.00003028",
|
|
1066
|
+
// "low":"0.00002935",
|
|
1067
|
+
// "avg":"0.00002963",
|
|
1068
|
+
// "vol":"1196546.3163222",
|
|
1069
|
+
// "vol_curr":"35.80066578",
|
|
1070
|
+
// "updated":1642291733
|
|
1071
|
+
// }
|
|
1072
|
+
//
|
|
1073
|
+
const timestamp = this.safeTimestamp(ticker, 'updated');
|
|
1074
|
+
market = this.safeMarket(undefined, market);
|
|
1075
|
+
const last = this.safeString(ticker, 'last_trade');
|
|
1076
|
+
return this.safeTicker({
|
|
1077
|
+
'symbol': market['symbol'],
|
|
1078
|
+
'timestamp': timestamp,
|
|
1079
|
+
'datetime': this.iso8601(timestamp),
|
|
1080
|
+
'high': this.safeString(ticker, 'high'),
|
|
1081
|
+
'low': this.safeString(ticker, 'low'),
|
|
1082
|
+
'bid': this.safeString(ticker, 'buy_price'),
|
|
1083
|
+
'bidVolume': undefined,
|
|
1084
|
+
'ask': this.safeString(ticker, 'sell_price'),
|
|
1085
|
+
'askVolume': undefined,
|
|
1086
|
+
'vwap': undefined,
|
|
1087
|
+
'open': undefined,
|
|
1088
|
+
'close': last,
|
|
1089
|
+
'last': last,
|
|
1090
|
+
'previousClose': undefined,
|
|
1091
|
+
'change': undefined,
|
|
1092
|
+
'percentage': undefined,
|
|
1093
|
+
'average': this.safeString(ticker, 'avg'),
|
|
1094
|
+
'baseVolume': this.safeString(ticker, 'vol'),
|
|
1095
|
+
'quoteVolume': this.safeString(ticker, 'vol_curr'),
|
|
1096
|
+
'info': ticker,
|
|
1097
|
+
}, market);
|
|
1098
|
+
}
|
|
1099
|
+
async fetchTickers(symbols = undefined, params = {}) {
|
|
1100
|
+
/**
|
|
1101
|
+
* @method
|
|
1102
|
+
* @name exmo#fetchTickers
|
|
1103
|
+
* @description fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
|
1104
|
+
* @param {string[]|undefined} symbols unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
|
1105
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1106
|
+
* @returns {object} a dictionary of [ticker structures]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
1107
|
+
*/
|
|
1108
|
+
await this.loadMarkets();
|
|
1109
|
+
symbols = this.marketSymbols(symbols);
|
|
1110
|
+
const response = await this.publicGetTicker(params);
|
|
1111
|
+
//
|
|
1112
|
+
// {
|
|
1113
|
+
// "ADA_BTC":{
|
|
1114
|
+
// "buy_price":"0.00002996",
|
|
1115
|
+
// "sell_price":"0.00003002",
|
|
1116
|
+
// "last_trade":"0.00002992",
|
|
1117
|
+
// "high":"0.00003028",
|
|
1118
|
+
// "low":"0.00002935",
|
|
1119
|
+
// "avg":"0.00002963",
|
|
1120
|
+
// "vol":"1196546.3163222",
|
|
1121
|
+
// "vol_curr":"35.80066578",
|
|
1122
|
+
// "updated":1642291733
|
|
1123
|
+
// }
|
|
1124
|
+
// }
|
|
1125
|
+
//
|
|
1126
|
+
const result = {};
|
|
1127
|
+
const marketIds = Object.keys(response);
|
|
1128
|
+
for (let i = 0; i < marketIds.length; i++) {
|
|
1129
|
+
const marketId = marketIds[i];
|
|
1130
|
+
const market = this.safeMarket(marketId, undefined, '_');
|
|
1131
|
+
const symbol = market['symbol'];
|
|
1132
|
+
const ticker = this.safeValue(response, marketId);
|
|
1133
|
+
result[symbol] = this.parseTicker(ticker, market);
|
|
1134
|
+
}
|
|
1135
|
+
return this.filterByArrayTickers(result, 'symbol', symbols);
|
|
1136
|
+
}
|
|
1137
|
+
async fetchTicker(symbol, params = {}) {
|
|
1138
|
+
/**
|
|
1139
|
+
* @method
|
|
1140
|
+
* @name exmo#fetchTicker
|
|
1141
|
+
* @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
1142
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
1143
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1144
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
1145
|
+
*/
|
|
1146
|
+
await this.loadMarkets();
|
|
1147
|
+
const response = await this.publicGetTicker(params);
|
|
1148
|
+
const market = this.market(symbol);
|
|
1149
|
+
return this.parseTicker(response[market['id']], market);
|
|
1150
|
+
}
|
|
1151
|
+
parseTrade(trade, market = undefined) {
|
|
1152
|
+
//
|
|
1153
|
+
// fetchTrades (public)
|
|
1154
|
+
//
|
|
1155
|
+
// {
|
|
1156
|
+
// "trade_id":165087520,
|
|
1157
|
+
// "date":1587470005,
|
|
1158
|
+
// "type":"buy",
|
|
1159
|
+
// "quantity":"1.004",
|
|
1160
|
+
// "price":"0.02491461",
|
|
1161
|
+
// "amount":"0.02501426"
|
|
1162
|
+
// },
|
|
1163
|
+
//
|
|
1164
|
+
// fetchMyTrades, fetchOrderTrades
|
|
1165
|
+
//
|
|
1166
|
+
// {
|
|
1167
|
+
// "trade_id": 3,
|
|
1168
|
+
// "date": 1435488248,
|
|
1169
|
+
// "type": "buy",
|
|
1170
|
+
// "pair": "BTC_USD",
|
|
1171
|
+
// "order_id": 12345,
|
|
1172
|
+
// "quantity": 1,
|
|
1173
|
+
// "price": 100,
|
|
1174
|
+
// "amount": 100,
|
|
1175
|
+
// "exec_type": "taker",
|
|
1176
|
+
// "commission_amount": "0.02",
|
|
1177
|
+
// "commission_currency": "BTC",
|
|
1178
|
+
// "commission_percent": "0.2"
|
|
1179
|
+
// }
|
|
1180
|
+
//
|
|
1181
|
+
// fetchMyTrades (margin)
|
|
1182
|
+
//
|
|
1183
|
+
// {
|
|
1184
|
+
// "trade_id": "692861757015952517",
|
|
1185
|
+
// "trade_dt": "1693951853197811824",
|
|
1186
|
+
// "trade_type": "buy",
|
|
1187
|
+
// "pair": "ADA_USDT",
|
|
1188
|
+
// "quantity": "1.96607879",
|
|
1189
|
+
// "price": "0.2568",
|
|
1190
|
+
// "amount": "0.50488903"
|
|
1191
|
+
// }
|
|
1192
|
+
//
|
|
1193
|
+
const timestamp = this.safeTimestamp(trade, 'date');
|
|
1194
|
+
const id = this.safeString(trade, 'trade_id');
|
|
1195
|
+
const orderId = this.safeString(trade, 'order_id');
|
|
1196
|
+
const priceString = this.safeString(trade, 'price');
|
|
1197
|
+
const amountString = this.safeString(trade, 'quantity');
|
|
1198
|
+
const costString = this.safeString(trade, 'amount');
|
|
1199
|
+
const side = this.safeString2(trade, 'type', 'trade_type');
|
|
1200
|
+
const type = undefined;
|
|
1201
|
+
const marketId = this.safeString(trade, 'pair');
|
|
1202
|
+
market = this.safeMarket(marketId, market, '_');
|
|
1203
|
+
const symbol = market['symbol'];
|
|
1204
|
+
const isMaker = this.safeValue(trade, 'is_maker');
|
|
1205
|
+
let takerOrMakerDefault = undefined;
|
|
1206
|
+
if (isMaker !== undefined) {
|
|
1207
|
+
takerOrMakerDefault = isMaker ? 'maker' : 'taker';
|
|
1208
|
+
}
|
|
1209
|
+
const takerOrMaker = this.safeString(trade, 'exec_type', takerOrMakerDefault);
|
|
1210
|
+
let fee = undefined;
|
|
1211
|
+
const feeCostString = this.safeString(trade, 'commission_amount');
|
|
1212
|
+
if (feeCostString !== undefined) {
|
|
1213
|
+
const feeCurrencyId = this.safeString(trade, 'commission_currency');
|
|
1214
|
+
const feeCurrencyCode = this.safeCurrencyCode(feeCurrencyId);
|
|
1215
|
+
let feeRateString = this.safeString(trade, 'commission_percent');
|
|
1216
|
+
if (feeRateString !== undefined) {
|
|
1217
|
+
feeRateString = Precise["default"].stringDiv(feeRateString, '1000', 18);
|
|
1218
|
+
}
|
|
1219
|
+
fee = {
|
|
1220
|
+
'cost': feeCostString,
|
|
1221
|
+
'currency': feeCurrencyCode,
|
|
1222
|
+
'rate': feeRateString,
|
|
1223
|
+
};
|
|
1224
|
+
}
|
|
1225
|
+
return this.safeTrade({
|
|
1226
|
+
'id': id,
|
|
1227
|
+
'info': trade,
|
|
1228
|
+
'timestamp': timestamp,
|
|
1229
|
+
'datetime': this.iso8601(timestamp),
|
|
1230
|
+
'symbol': symbol,
|
|
1231
|
+
'order': orderId,
|
|
1232
|
+
'type': type,
|
|
1233
|
+
'side': side,
|
|
1234
|
+
'takerOrMaker': takerOrMaker,
|
|
1235
|
+
'price': priceString,
|
|
1236
|
+
'amount': amountString,
|
|
1237
|
+
'cost': costString,
|
|
1238
|
+
'fee': fee,
|
|
1239
|
+
}, market);
|
|
1240
|
+
}
|
|
1241
|
+
async fetchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
1242
|
+
/**
|
|
1243
|
+
* @method
|
|
1244
|
+
* @name exmo#fetchTrades
|
|
1245
|
+
* @description get the list of most recent trades for a particular symbol
|
|
1246
|
+
* @param {string} symbol unified symbol of the market to fetch trades for
|
|
1247
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch
|
|
1248
|
+
* @param {int} [limit] the maximum amount of trades to fetch
|
|
1249
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1250
|
+
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
|
|
1251
|
+
*/
|
|
1252
|
+
await this.loadMarkets();
|
|
1253
|
+
const market = this.market(symbol);
|
|
1254
|
+
const request = {
|
|
1255
|
+
'pair': market['id'],
|
|
1256
|
+
};
|
|
1257
|
+
const response = await this.publicGetTrades(this.extend(request, params));
|
|
1258
|
+
//
|
|
1259
|
+
// {
|
|
1260
|
+
// "ETH_BTC":[
|
|
1261
|
+
// {
|
|
1262
|
+
// "trade_id":165087520,
|
|
1263
|
+
// "date":1587470005,
|
|
1264
|
+
// "type":"buy",
|
|
1265
|
+
// "quantity":"1.004",
|
|
1266
|
+
// "price":"0.02491461",
|
|
1267
|
+
// "amount":"0.02501426"
|
|
1268
|
+
// },
|
|
1269
|
+
// {
|
|
1270
|
+
// "trade_id":165087369,
|
|
1271
|
+
// "date":1587469938,
|
|
1272
|
+
// "type":"buy",
|
|
1273
|
+
// "quantity":"0.94",
|
|
1274
|
+
// "price":"0.02492348",
|
|
1275
|
+
// "amount":"0.02342807"
|
|
1276
|
+
// }
|
|
1277
|
+
// ]
|
|
1278
|
+
// }
|
|
1279
|
+
//
|
|
1280
|
+
const data = this.safeValue(response, market['id'], []);
|
|
1281
|
+
return this.parseTrades(data, market, since, limit);
|
|
1282
|
+
}
|
|
1283
|
+
async fetchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1284
|
+
/**
|
|
1285
|
+
* @method
|
|
1286
|
+
* @name exmo#fetchMyTrades
|
|
1287
|
+
* @description fetch all trades made by the user
|
|
1288
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#b8d8d9af-4f46-46a1-939b-ad261d79f452 // spot
|
|
1289
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#f4b1aaf8-399f-403b-ab5e-4926d967a106 // margin
|
|
1290
|
+
* @param {string} symbol a symbol is required but it can be a single string, or a non-empty array
|
|
1291
|
+
* @param {int} [since] the earliest time in ms to fetch trades for
|
|
1292
|
+
* @param {int} [limit] *required for margin orders* the maximum number of trades structures to retrieve
|
|
1293
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1294
|
+
*
|
|
1295
|
+
* EXCHANGE SPECIFIC PARAMETERS
|
|
1296
|
+
* @param {int} [params.offset] last deal offset, default = 0
|
|
1297
|
+
* @returns {Trade[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
|
|
1298
|
+
*/
|
|
1299
|
+
if (symbol === undefined) {
|
|
1300
|
+
throw new errors.ArgumentsRequired(this.id + ' fetchMyTrades() requires a symbol argument');
|
|
1301
|
+
}
|
|
1302
|
+
let marginMode = undefined;
|
|
1303
|
+
[marginMode, params] = this.handleMarginModeAndParams('fetchMyTrades', params);
|
|
1304
|
+
if (marginMode === 'cross') {
|
|
1305
|
+
throw new errors.BadRequest(this.id + 'only isolated margin is supported');
|
|
1306
|
+
}
|
|
1307
|
+
await this.loadMarkets();
|
|
1308
|
+
const market = this.market(symbol);
|
|
1309
|
+
const pair = market['id'];
|
|
1310
|
+
const isSpot = marginMode !== 'isolated';
|
|
1311
|
+
if (limit === undefined) {
|
|
1312
|
+
limit = 100;
|
|
1313
|
+
}
|
|
1314
|
+
const request = {};
|
|
1315
|
+
if (isSpot) {
|
|
1316
|
+
request['pair'] = pair;
|
|
1317
|
+
}
|
|
1318
|
+
else {
|
|
1319
|
+
request['pair_name'] = pair;
|
|
1320
|
+
}
|
|
1321
|
+
if (limit !== undefined) {
|
|
1322
|
+
request['limit'] = limit;
|
|
1323
|
+
}
|
|
1324
|
+
const offset = this.safeInteger(params, 'offset', 0);
|
|
1325
|
+
request['offset'] = offset;
|
|
1326
|
+
let response = undefined;
|
|
1327
|
+
if (isSpot) {
|
|
1328
|
+
response = await this.privatePostUserTrades(this.extend(request, params));
|
|
1329
|
+
//
|
|
1330
|
+
// {
|
|
1331
|
+
// "BTC_USD": [
|
|
1332
|
+
// {
|
|
1333
|
+
// "trade_id": 20056872,
|
|
1334
|
+
// "client_id": 100500,
|
|
1335
|
+
// "date": 1435488248,
|
|
1336
|
+
// "type": "buy",
|
|
1337
|
+
// "pair": "BTC_USD",
|
|
1338
|
+
// "quantity": "1",
|
|
1339
|
+
// "price": "100",
|
|
1340
|
+
// "amount": "100",
|
|
1341
|
+
// "order_id": 7,
|
|
1342
|
+
// "parent_order_id": 117684023830293,
|
|
1343
|
+
// "exec_type": "taker",
|
|
1344
|
+
// "commission_amount": "0.02",
|
|
1345
|
+
// "commission_currency": "BTC",
|
|
1346
|
+
// "commission_percent": "0.2"
|
|
1347
|
+
// }
|
|
1348
|
+
// ],
|
|
1349
|
+
// ...
|
|
1350
|
+
// }
|
|
1351
|
+
//
|
|
1352
|
+
}
|
|
1353
|
+
else {
|
|
1354
|
+
const responseFromExchange = await this.privatePostMarginTrades(this.extend(request, params));
|
|
1355
|
+
//
|
|
1356
|
+
// {
|
|
1357
|
+
// "trades": {
|
|
1358
|
+
// "ADA_USDT": [
|
|
1359
|
+
// {
|
|
1360
|
+
// "trade_id": "692861757015952517",
|
|
1361
|
+
// "trade_dt": "1693951853197811824",
|
|
1362
|
+
// "trade_type": "buy",
|
|
1363
|
+
// "pair": "ADA_USDT",
|
|
1364
|
+
// "quantity": "1.96607879",
|
|
1365
|
+
// "price": "0.2568",
|
|
1366
|
+
// "amount": "0.50488903"
|
|
1367
|
+
// },
|
|
1368
|
+
// ]
|
|
1369
|
+
// ...
|
|
1370
|
+
// }
|
|
1371
|
+
// }
|
|
1372
|
+
//
|
|
1373
|
+
response = this.safeValue(responseFromExchange, 'trades');
|
|
1374
|
+
}
|
|
1375
|
+
let result = [];
|
|
1376
|
+
const marketIdsInner = Object.keys(response);
|
|
1377
|
+
for (let i = 0; i < marketIdsInner.length; i++) {
|
|
1378
|
+
const marketId = marketIdsInner[i];
|
|
1379
|
+
const resultMarket = this.safeMarket(marketId, undefined, '_');
|
|
1380
|
+
const items = response[marketId];
|
|
1381
|
+
const trades = this.parseTrades(items, resultMarket, since, limit);
|
|
1382
|
+
result = this.arrayConcat(result, trades);
|
|
1383
|
+
}
|
|
1384
|
+
return this.filterBySinceLimit(result, since, limit);
|
|
1385
|
+
}
|
|
1386
|
+
async createOrder(symbol, type, side, amount, price = undefined, params = {}) {
|
|
1387
|
+
/**
|
|
1388
|
+
* @method
|
|
1389
|
+
* @name exmo#createOrder
|
|
1390
|
+
* @description create a trade order
|
|
1391
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#80daa469-ec59-4d0a-b229-6a311d8dd1cd
|
|
1392
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#de6f4321-eeac-468c-87f7-c4ad7062e265 // stop market
|
|
1393
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#3561b86c-9ff1-436e-8e68-ac926b7eb523 // margin
|
|
1394
|
+
* @param {string} symbol unified symbol of the market to create an order in
|
|
1395
|
+
* @param {string} type 'market' or 'limit'
|
|
1396
|
+
* @param {string} side 'buy' or 'sell'
|
|
1397
|
+
* @param {float} amount how much of currency you want to trade in units of base currency
|
|
1398
|
+
* @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
1399
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1400
|
+
* @param {float} [params.stopPrice] the price at which a trigger order is triggered at
|
|
1401
|
+
* @param {string} [params.timeInForce] *spot only* 'fok', 'ioc' or 'post_only'
|
|
1402
|
+
* @param {boolean} [params.postOnly] *spot only* true for post only orders
|
|
1403
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1404
|
+
*/
|
|
1405
|
+
await this.loadMarkets();
|
|
1406
|
+
const market = this.market(symbol);
|
|
1407
|
+
const isMarket = (type === 'market') && (price === undefined);
|
|
1408
|
+
let marginMode = undefined;
|
|
1409
|
+
[marginMode, params] = this.handleMarginModeAndParams('createOrder', params);
|
|
1410
|
+
if (marginMode === 'cross') {
|
|
1411
|
+
throw new errors.BadRequest(this.id + ' only supports isolated margin');
|
|
1412
|
+
}
|
|
1413
|
+
const isSpot = (marginMode !== 'isolated');
|
|
1414
|
+
const triggerPrice = this.safeNumberN(params, ['triggerPrice', 'stopPrice', 'stop_price']);
|
|
1415
|
+
const request = {
|
|
1416
|
+
'pair': market['id'],
|
|
1417
|
+
// 'leverage': 2,
|
|
1418
|
+
'quantity': this.amountToPrecision(market['symbol'], amount),
|
|
1419
|
+
// spot - buy, sell, market_buy, market_sell, market_buy_total, market_sell_total
|
|
1420
|
+
// margin - limit_buy, limit_sell, market_buy, market_sell, stop_buy, stop_sell, stop_limit_buy, stop_limit_sell, trailing_stop_buy, trailing_stop_sell
|
|
1421
|
+
// 'stop_price': this.priceToPrecision (symbol, stopPrice),
|
|
1422
|
+
// 'distance': 0, // distance for trailing stop orders
|
|
1423
|
+
// 'expire': 0, // expiration timestamp in UTC timezone for the order, unless expire is 0
|
|
1424
|
+
// 'client_id': 123, // optional, must be a positive integer
|
|
1425
|
+
// 'comment': '', // up to 50 latin symbols, whitespaces, underscores
|
|
1426
|
+
};
|
|
1427
|
+
let clientOrderId = this.safeValue2(params, 'client_id', 'clientOrderId');
|
|
1428
|
+
if (clientOrderId !== undefined) {
|
|
1429
|
+
clientOrderId = this.safeInteger2(params, 'client_id', 'clientOrderId');
|
|
1430
|
+
if (clientOrderId === undefined) {
|
|
1431
|
+
throw new errors.BadRequest(this.id + ' createOrder() client order id must be an integer / numeric literal');
|
|
1432
|
+
}
|
|
1433
|
+
else {
|
|
1434
|
+
request['client_id'] = clientOrderId;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
const leverage = this.safeNumber(params, 'leverage');
|
|
1438
|
+
if (!isSpot && (leverage === undefined)) {
|
|
1439
|
+
throw new errors.ArgumentsRequired(this.id + ' createOrder requires an extra param params["leverage"] for margin orders');
|
|
1440
|
+
}
|
|
1441
|
+
params = this.omit(params, ['stopPrice', 'stop_price', 'triggerPrice', 'timeInForce', 'client_id', 'clientOrderId']);
|
|
1442
|
+
if (price !== undefined) {
|
|
1443
|
+
request['price'] = this.priceToPrecision(market['symbol'], price);
|
|
1444
|
+
}
|
|
1445
|
+
let response = undefined;
|
|
1446
|
+
if (isSpot) {
|
|
1447
|
+
if (triggerPrice !== undefined) {
|
|
1448
|
+
if (type === 'limit') {
|
|
1449
|
+
throw new errors.BadRequest(this.id + ' createOrder () cannot create stop limit orders for spot, only stop market');
|
|
1450
|
+
}
|
|
1451
|
+
else {
|
|
1452
|
+
request['type'] = side;
|
|
1453
|
+
request['trigger_price'] = this.priceToPrecision(symbol, triggerPrice);
|
|
1454
|
+
}
|
|
1455
|
+
response = await this.privatePostStopMarketOrderCreate(this.extend(request, params));
|
|
1456
|
+
}
|
|
1457
|
+
else {
|
|
1458
|
+
const execType = this.safeString(params, 'exec_type');
|
|
1459
|
+
let isPostOnly = undefined;
|
|
1460
|
+
[isPostOnly, params] = this.handlePostOnly(type === 'market', execType === 'post_only', params);
|
|
1461
|
+
const timeInForce = this.safeString(params, 'timeInForce');
|
|
1462
|
+
request['price'] = isMarket ? 0 : this.priceToPrecision(market['symbol'], price);
|
|
1463
|
+
if (type === 'limit') {
|
|
1464
|
+
request['type'] = side;
|
|
1465
|
+
}
|
|
1466
|
+
else if (type === 'market') {
|
|
1467
|
+
request['type'] = 'market_' + side;
|
|
1468
|
+
}
|
|
1469
|
+
if (isPostOnly) {
|
|
1470
|
+
request['exec_type'] = 'post_only';
|
|
1471
|
+
}
|
|
1472
|
+
else if (timeInForce !== undefined) {
|
|
1473
|
+
request['exec_type'] = timeInForce;
|
|
1474
|
+
}
|
|
1475
|
+
response = await this.privatePostOrderCreate(this.extend(request, params));
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1478
|
+
else {
|
|
1479
|
+
if (triggerPrice !== undefined) {
|
|
1480
|
+
request['stop_price'] = this.priceToPrecision(symbol, triggerPrice);
|
|
1481
|
+
if (type === 'limit') {
|
|
1482
|
+
request['type'] = 'stop_limit_' + side;
|
|
1483
|
+
}
|
|
1484
|
+
else if (type === 'market') {
|
|
1485
|
+
request['type'] = 'stop_' + side;
|
|
1486
|
+
}
|
|
1487
|
+
else {
|
|
1488
|
+
request['type'] = type;
|
|
1489
|
+
}
|
|
1490
|
+
}
|
|
1491
|
+
else {
|
|
1492
|
+
if (type === 'limit' || type === 'market') {
|
|
1493
|
+
request['type'] = type + '_' + side;
|
|
1494
|
+
}
|
|
1495
|
+
else {
|
|
1496
|
+
request['type'] = type;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
response = await this.privatePostMarginUserOrderCreate(this.extend(request, params));
|
|
1500
|
+
}
|
|
1501
|
+
return this.parseOrder(response, market);
|
|
1502
|
+
}
|
|
1503
|
+
async cancelOrder(id, symbol = undefined, params = {}) {
|
|
1504
|
+
/**
|
|
1505
|
+
* @method
|
|
1506
|
+
* @name exmo#cancelOrder
|
|
1507
|
+
* @description cancels an open order
|
|
1508
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#1f710d4b-75bc-4b65-ad68-006f863a3f26
|
|
1509
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#a4d0aae8-28f7-41ac-94fd-c4030130453d // stop market
|
|
1510
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#705dfec5-2b35-4667-862b-faf54eca6209 // margin
|
|
1511
|
+
* @param {string} id order id
|
|
1512
|
+
* @param {string} symbol not used by exmo cancelOrder ()
|
|
1513
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1514
|
+
* @param {boolean} [params.trigger] true to cancel a trigger order
|
|
1515
|
+
* @param {string} [params.marginMode] set to 'cross' or 'isolated' to cancel a margin order
|
|
1516
|
+
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1517
|
+
*/
|
|
1518
|
+
await this.loadMarkets();
|
|
1519
|
+
const request = {};
|
|
1520
|
+
const stop = this.safeValue2(params, 'trigger', 'stop');
|
|
1521
|
+
params = this.omit(params, ['trigger', 'stop']);
|
|
1522
|
+
let marginMode = undefined;
|
|
1523
|
+
[marginMode, params] = this.handleMarginModeAndParams('cancelOrder', params);
|
|
1524
|
+
if (marginMode === 'cross') {
|
|
1525
|
+
throw new errors.BadRequest(this.id + ' only supports isolated margin');
|
|
1526
|
+
}
|
|
1527
|
+
let response = undefined;
|
|
1528
|
+
if ((marginMode === 'isolated')) {
|
|
1529
|
+
request['order_id'] = id;
|
|
1530
|
+
response = await this.privatePostMarginUserOrderCancel(this.extend(request, params));
|
|
1531
|
+
//
|
|
1532
|
+
// {}
|
|
1533
|
+
//
|
|
1534
|
+
}
|
|
1535
|
+
else {
|
|
1536
|
+
if (stop) {
|
|
1537
|
+
request['parent_order_id'] = id;
|
|
1538
|
+
response = await this.privatePostStopMarketOrderCancel(this.extend(request, params));
|
|
1539
|
+
//
|
|
1540
|
+
// {}
|
|
1541
|
+
//
|
|
1542
|
+
}
|
|
1543
|
+
else {
|
|
1544
|
+
request['order_id'] = id;
|
|
1545
|
+
response = await this.privatePostOrderCancel(this.extend(request, params));
|
|
1546
|
+
//
|
|
1547
|
+
// {
|
|
1548
|
+
// "error": '',
|
|
1549
|
+
// "result": True
|
|
1550
|
+
// }
|
|
1551
|
+
//
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
return this.parseOrder(response);
|
|
1555
|
+
}
|
|
1556
|
+
async fetchOrder(id, symbol = undefined, params = {}) {
|
|
1557
|
+
/**
|
|
1558
|
+
* @method
|
|
1559
|
+
* @name exmo#fetchOrder
|
|
1560
|
+
* @description *spot only* fetches information on an order made by the user
|
|
1561
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#cf27781e-28e5-4b39-a52d-3110f5d22459 // spot
|
|
1562
|
+
* @param {string} symbol not used by exmo fetchOrder
|
|
1563
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1564
|
+
* @returns {object} An [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1565
|
+
*/
|
|
1566
|
+
await this.loadMarkets();
|
|
1567
|
+
const request = {
|
|
1568
|
+
'order_id': id.toString(),
|
|
1569
|
+
};
|
|
1570
|
+
const response = await this.privatePostOrderTrades(this.extend(request, params));
|
|
1571
|
+
//
|
|
1572
|
+
// {
|
|
1573
|
+
// "type": "buy",
|
|
1574
|
+
// "in_currency": "BTC",
|
|
1575
|
+
// "in_amount": "1",
|
|
1576
|
+
// "out_currency": "USD",
|
|
1577
|
+
// "out_amount": "100",
|
|
1578
|
+
// "trades": [
|
|
1579
|
+
// {
|
|
1580
|
+
// "trade_id": 3,
|
|
1581
|
+
// "date": 1435488248,
|
|
1582
|
+
// "type": "buy",
|
|
1583
|
+
// "pair": "BTC_USD",
|
|
1584
|
+
// "order_id": 12345,
|
|
1585
|
+
// "quantity": 1,
|
|
1586
|
+
// "price": 100,
|
|
1587
|
+
// "amount": 100
|
|
1588
|
+
// }
|
|
1589
|
+
// ]
|
|
1590
|
+
// }
|
|
1591
|
+
//
|
|
1592
|
+
const order = this.parseOrder(response);
|
|
1593
|
+
order['id'] = id.toString();
|
|
1594
|
+
return order;
|
|
1595
|
+
}
|
|
1596
|
+
async fetchOrderTrades(id, symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1597
|
+
/**
|
|
1598
|
+
* @method
|
|
1599
|
+
* @name exmo#fetchOrderTrades
|
|
1600
|
+
* @description fetch all the trades made from a single order
|
|
1601
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#cf27781e-28e5-4b39-a52d-3110f5d22459 // spot
|
|
1602
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#00810661-9119-46c5-aec5-55abe9cb42c7 // margin
|
|
1603
|
+
* @param {string} id order id
|
|
1604
|
+
* @param {string} symbol unified market symbol
|
|
1605
|
+
* @param {int} [since] the earliest time in ms to fetch trades for
|
|
1606
|
+
* @param {int} [limit] the maximum number of trades to retrieve
|
|
1607
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1608
|
+
* @param {string} [params.marginMode] set to "isolated" to fetch trades for a margin order
|
|
1609
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
|
|
1610
|
+
*/
|
|
1611
|
+
let marginMode = undefined;
|
|
1612
|
+
[marginMode, params] = this.handleMarginModeAndParams('fetchOrderTrades', params);
|
|
1613
|
+
if (marginMode === 'cross') {
|
|
1614
|
+
throw new errors.BadRequest(this.id + ' only supports isolated margin');
|
|
1615
|
+
}
|
|
1616
|
+
let market = undefined;
|
|
1617
|
+
if (symbol !== undefined) {
|
|
1618
|
+
market = this.market(symbol);
|
|
1619
|
+
}
|
|
1620
|
+
const request = {
|
|
1621
|
+
'order_id': id.toString(),
|
|
1622
|
+
};
|
|
1623
|
+
let response = undefined;
|
|
1624
|
+
if (marginMode === 'isolated') {
|
|
1625
|
+
response = await this.privatePostMarginUserOrderTrades(this.extend(request, params));
|
|
1626
|
+
//
|
|
1627
|
+
// {
|
|
1628
|
+
// "trades": [
|
|
1629
|
+
// {
|
|
1630
|
+
// "is_maker": false,
|
|
1631
|
+
// "order_id": "123",
|
|
1632
|
+
// "pair": "BTC_USD",
|
|
1633
|
+
// "price": "54122.25",
|
|
1634
|
+
// "quantity": "0.00069994",
|
|
1635
|
+
// "trade_dt": "1619069561718824428",
|
|
1636
|
+
// "trade_id": "692842802860135010",
|
|
1637
|
+
// "type": "sell"
|
|
1638
|
+
// }
|
|
1639
|
+
// ]
|
|
1640
|
+
// }
|
|
1641
|
+
//
|
|
1642
|
+
}
|
|
1643
|
+
else {
|
|
1644
|
+
response = await this.privatePostOrderTrades(this.extend(request, params));
|
|
1645
|
+
//
|
|
1646
|
+
// {
|
|
1647
|
+
// "type": "buy",
|
|
1648
|
+
// "in_currency": "BTC",
|
|
1649
|
+
// "in_amount": "1",
|
|
1650
|
+
// "out_currency": "USD",
|
|
1651
|
+
// "out_amount": "100",
|
|
1652
|
+
// "trades": [
|
|
1653
|
+
// {
|
|
1654
|
+
// "trade_id": 3,
|
|
1655
|
+
// "date": 1435488248,
|
|
1656
|
+
// "type": "buy",
|
|
1657
|
+
// "pair": "BTC_USD",
|
|
1658
|
+
// "order_id": 12345,
|
|
1659
|
+
// "quantity": 1,
|
|
1660
|
+
// "price": 100,
|
|
1661
|
+
// "amount": 100,
|
|
1662
|
+
// "exec_type": "taker",
|
|
1663
|
+
// "commission_amount": "0.02",
|
|
1664
|
+
// "commission_currency": "BTC",
|
|
1665
|
+
// "commission_percent": "0.2"
|
|
1666
|
+
// }
|
|
1667
|
+
// ]
|
|
1668
|
+
// }
|
|
1669
|
+
//
|
|
1670
|
+
}
|
|
1671
|
+
const trades = this.safeValue(response, 'trades');
|
|
1672
|
+
return this.parseTrades(trades, market, since, limit);
|
|
1673
|
+
}
|
|
1674
|
+
async fetchOpenOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1675
|
+
/**
|
|
1676
|
+
* @method
|
|
1677
|
+
* @name exmo#fetchOpenOrders
|
|
1678
|
+
* @description fetch all unfilled currently open orders
|
|
1679
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#0e135370-daa4-4689-8acd-b6876dee9ba1 // spot open orders
|
|
1680
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#a7cfd4f0-476e-4675-b33f-22a46902f245 // margin
|
|
1681
|
+
* @param {string} symbol unified market symbol
|
|
1682
|
+
* @param {int} [since] the earliest time in ms to fetch open orders for
|
|
1683
|
+
* @param {int} [limit] the maximum number of open orders structures to retrieve
|
|
1684
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1685
|
+
* @param {string} [params.marginMode] set to "isolated" for margin orders
|
|
1686
|
+
* @returns {Order[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1687
|
+
*/
|
|
1688
|
+
await this.loadMarkets();
|
|
1689
|
+
let market = undefined;
|
|
1690
|
+
if (symbol !== undefined) {
|
|
1691
|
+
market = this.market(symbol);
|
|
1692
|
+
symbol = market['symbol'];
|
|
1693
|
+
}
|
|
1694
|
+
let marginMode = undefined;
|
|
1695
|
+
[marginMode, params] = this.handleMarginModeAndParams('fetchOpenOrders', params);
|
|
1696
|
+
const isMargin = ((marginMode === 'cross') || (marginMode === 'isolated'));
|
|
1697
|
+
let response = undefined;
|
|
1698
|
+
let orders = [];
|
|
1699
|
+
if (isMargin) {
|
|
1700
|
+
response = await this.privatePostMarginUserOrderList(params);
|
|
1701
|
+
//
|
|
1702
|
+
// {
|
|
1703
|
+
// "orders": [
|
|
1704
|
+
// {
|
|
1705
|
+
// "client_id": "0",
|
|
1706
|
+
// "comment": "",
|
|
1707
|
+
// "created": "1619068707985325495",
|
|
1708
|
+
// "distance": "0",
|
|
1709
|
+
// "expire": 0,
|
|
1710
|
+
// "funding_currency": "BTC",
|
|
1711
|
+
// "funding_quantity": "0.01",
|
|
1712
|
+
// "funding_rate": "0.02",
|
|
1713
|
+
// "leverage": "2",
|
|
1714
|
+
// "order_id": "123",
|
|
1715
|
+
// "pair": "BTC_USD",
|
|
1716
|
+
// "previous_type": "limit_sell",
|
|
1717
|
+
// "price": "58000",
|
|
1718
|
+
// "quantity": "0.01",
|
|
1719
|
+
// "src": 0,
|
|
1720
|
+
// "stop_price": "0",
|
|
1721
|
+
// "trigger_price": "58000",
|
|
1722
|
+
// "type": "limit_sell",
|
|
1723
|
+
// "updated": 1619068707989411800
|
|
1724
|
+
// }
|
|
1725
|
+
// ]
|
|
1726
|
+
// }
|
|
1727
|
+
//
|
|
1728
|
+
params = this.extend(params, {
|
|
1729
|
+
'status': 'open',
|
|
1730
|
+
});
|
|
1731
|
+
const responseOrders = this.safeValue(response, 'orders');
|
|
1732
|
+
orders = this.parseOrders(responseOrders, market, since, limit, params);
|
|
1733
|
+
}
|
|
1734
|
+
else {
|
|
1735
|
+
response = await this.privatePostUserOpenOrders(params);
|
|
1736
|
+
//
|
|
1737
|
+
// {
|
|
1738
|
+
// "USDT_USD": [
|
|
1739
|
+
// {
|
|
1740
|
+
// "parent_order_id": "507061384740151010",
|
|
1741
|
+
// "client_id": "100500",
|
|
1742
|
+
// "created": "1589547391",
|
|
1743
|
+
// "type": "stop_market_buy",
|
|
1744
|
+
// "pair": "USDT_USD",
|
|
1745
|
+
// "quantity": "1",
|
|
1746
|
+
// "trigger_price": "5",
|
|
1747
|
+
// "amount": "5"
|
|
1748
|
+
// }
|
|
1749
|
+
// ],
|
|
1750
|
+
// ...
|
|
1751
|
+
// }
|
|
1752
|
+
//
|
|
1753
|
+
const marketIds = Object.keys(response);
|
|
1754
|
+
for (let i = 0; i < marketIds.length; i++) {
|
|
1755
|
+
const marketId = marketIds[i];
|
|
1756
|
+
const marketInner = this.safeMarket(marketId);
|
|
1757
|
+
params = this.extend(params, {
|
|
1758
|
+
'status': 'open',
|
|
1759
|
+
});
|
|
1760
|
+
const parsedOrders = this.parseOrders(response[marketId], marketInner, since, limit, params);
|
|
1761
|
+
orders = this.arrayConcat(orders, parsedOrders);
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
return orders;
|
|
1765
|
+
}
|
|
1766
|
+
parseStatus(status) {
|
|
1767
|
+
if (status === undefined) {
|
|
1768
|
+
return undefined;
|
|
1769
|
+
}
|
|
1770
|
+
const statuses = {
|
|
1771
|
+
'cancel_started': 'canceled',
|
|
1772
|
+
};
|
|
1773
|
+
if (status.indexOf('cancel') >= 0) {
|
|
1774
|
+
status = 'canceled';
|
|
1775
|
+
}
|
|
1776
|
+
return this.safeString(statuses, status, status);
|
|
1777
|
+
}
|
|
1778
|
+
parseSide(orderType) {
|
|
1779
|
+
const side = {
|
|
1780
|
+
'limit_buy': 'buy',
|
|
1781
|
+
'limit_sell': 'sell',
|
|
1782
|
+
'market_buy': 'buy',
|
|
1783
|
+
'market_sell': 'sell',
|
|
1784
|
+
'stop_buy': 'buy',
|
|
1785
|
+
'stop_sell': 'sell',
|
|
1786
|
+
'stop_limit_buy': 'buy',
|
|
1787
|
+
'stop_limit_sell': 'sell',
|
|
1788
|
+
'trailing_stop_buy': 'buy',
|
|
1789
|
+
'trailing_stop_sell': 'sell',
|
|
1790
|
+
'stop_market_sell': 'sell',
|
|
1791
|
+
'stop_market_buy': 'buy',
|
|
1792
|
+
'buy': 'buy',
|
|
1793
|
+
'sell': 'sell',
|
|
1794
|
+
};
|
|
1795
|
+
return this.safeString(side, orderType, orderType);
|
|
1796
|
+
}
|
|
1797
|
+
parseOrder(order, market = undefined) {
|
|
1798
|
+
//
|
|
1799
|
+
// fetchOrders, fetchOpenOrders, fetchClosedOrders, fetchCanceledOrders
|
|
1800
|
+
//
|
|
1801
|
+
// {
|
|
1802
|
+
// "order_id": "14",
|
|
1803
|
+
// "created": "1435517311",
|
|
1804
|
+
// "type": "buy",
|
|
1805
|
+
// "pair": "BTC_USD",
|
|
1806
|
+
// "price": "100",
|
|
1807
|
+
// "quantity": "1",
|
|
1808
|
+
// "amount": "100"
|
|
1809
|
+
// }
|
|
1810
|
+
//
|
|
1811
|
+
// fetchOrder
|
|
1812
|
+
//
|
|
1813
|
+
// {
|
|
1814
|
+
// "type": "buy",
|
|
1815
|
+
// "in_currency": "BTC",
|
|
1816
|
+
// "in_amount": "1",
|
|
1817
|
+
// "out_currency": "USD",
|
|
1818
|
+
// "out_amount": "100",
|
|
1819
|
+
// "trades": [
|
|
1820
|
+
// {
|
|
1821
|
+
// "trade_id": 3,
|
|
1822
|
+
// "date": 1435488248,
|
|
1823
|
+
// "type": "buy",
|
|
1824
|
+
// "pair": "BTC_USD",
|
|
1825
|
+
// "order_id": 12345,
|
|
1826
|
+
// "quantity": 1,
|
|
1827
|
+
// "price": 100,
|
|
1828
|
+
// "amount": 100
|
|
1829
|
+
// }
|
|
1830
|
+
// ]
|
|
1831
|
+
// }
|
|
1832
|
+
//
|
|
1833
|
+
// Margin fetchOpenOrders
|
|
1834
|
+
//
|
|
1835
|
+
// {
|
|
1836
|
+
// "client_id": "0",
|
|
1837
|
+
// "comment": "",
|
|
1838
|
+
// "created": "1619068707985325495",
|
|
1839
|
+
// "distance": "0",
|
|
1840
|
+
// "expire": 0,
|
|
1841
|
+
// "funding_currency": "BTC",
|
|
1842
|
+
// "funding_quantity": "0.01",
|
|
1843
|
+
// "funding_rate": "0.02",
|
|
1844
|
+
// "leverage": "2",
|
|
1845
|
+
// "order_id": "123",
|
|
1846
|
+
// "pair": "BTC_USD",
|
|
1847
|
+
// "previous_type": "limit_sell",
|
|
1848
|
+
// "price": "58000",
|
|
1849
|
+
// "quantity": "0.01",
|
|
1850
|
+
// "src": 0,
|
|
1851
|
+
// "stop_price": "0",
|
|
1852
|
+
// "trigger_price": "58000",
|
|
1853
|
+
// "type": "limit_sell",
|
|
1854
|
+
// "updated": 1619068707989411800
|
|
1855
|
+
// }
|
|
1856
|
+
//
|
|
1857
|
+
// Margin fetchClosedOrders
|
|
1858
|
+
//
|
|
1859
|
+
// {
|
|
1860
|
+
// "distance": "0",
|
|
1861
|
+
// "event_id": "692842802860022508",
|
|
1862
|
+
// "event_time": "1619069531190173720",
|
|
1863
|
+
// "event_type": "OrderCancelStarted",
|
|
1864
|
+
// "order_id": "123",
|
|
1865
|
+
// "order_status": "cancel_started",
|
|
1866
|
+
// "order_type": "limit_sell",
|
|
1867
|
+
// "pair": "BTC_USD",
|
|
1868
|
+
// "price": "54115",
|
|
1869
|
+
// "quantity": "0.001",
|
|
1870
|
+
// "stop_price": "0",
|
|
1871
|
+
// "trade_id": "0",
|
|
1872
|
+
// "trade_price": "0",
|
|
1873
|
+
// "trade_quantity": "0",
|
|
1874
|
+
// "trade_type": ""
|
|
1875
|
+
// },
|
|
1876
|
+
//
|
|
1877
|
+
const id = this.safeString2(order, 'order_id', 'parent_order_id');
|
|
1878
|
+
const eventTime = this.safeIntegerProduct2(order, 'event_time', 'created', 0.000001);
|
|
1879
|
+
const timestamp = this.safeTimestamp(order, 'created', eventTime);
|
|
1880
|
+
const orderType = this.safeString2(order, 'type', 'order_type');
|
|
1881
|
+
const side = this.parseSide(orderType);
|
|
1882
|
+
let marketId = undefined;
|
|
1883
|
+
if ('pair' in order) {
|
|
1884
|
+
marketId = order['pair'];
|
|
1885
|
+
}
|
|
1886
|
+
else if (('in_currency' in order) && ('out_currency' in order)) {
|
|
1887
|
+
if (side === 'buy') {
|
|
1888
|
+
marketId = order['in_currency'] + '_' + order['out_currency'];
|
|
1889
|
+
}
|
|
1890
|
+
else {
|
|
1891
|
+
marketId = order['out_currency'] + '_' + order['in_currency'];
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
market = this.safeMarket(marketId, market);
|
|
1895
|
+
const symbol = market['symbol'];
|
|
1896
|
+
let amount = this.safeString(order, 'quantity');
|
|
1897
|
+
if (amount === undefined) {
|
|
1898
|
+
const amountField = (side === 'buy') ? 'in_amount' : 'out_amount';
|
|
1899
|
+
amount = this.safeString(order, amountField);
|
|
1900
|
+
}
|
|
1901
|
+
const price = this.safeString(order, 'price');
|
|
1902
|
+
const cost = this.safeString(order, 'amount');
|
|
1903
|
+
const transactions = this.safeValue(order, 'trades', []);
|
|
1904
|
+
const clientOrderId = this.safeInteger(order, 'client_id');
|
|
1905
|
+
let triggerPrice = this.safeString(order, 'stop_price');
|
|
1906
|
+
if (triggerPrice === '0') {
|
|
1907
|
+
triggerPrice = undefined;
|
|
1908
|
+
}
|
|
1909
|
+
let type = undefined;
|
|
1910
|
+
if ((orderType !== 'buy') && (orderType !== 'sell')) {
|
|
1911
|
+
type = orderType;
|
|
1912
|
+
}
|
|
1913
|
+
return this.safeOrder({
|
|
1914
|
+
'id': id,
|
|
1915
|
+
'clientOrderId': clientOrderId,
|
|
1916
|
+
'datetime': this.iso8601(timestamp),
|
|
1917
|
+
'timestamp': timestamp,
|
|
1918
|
+
'lastTradeTimestamp': this.safeIntegerProduct(order, 'updated', 0.000001),
|
|
1919
|
+
'status': this.parseStatus(this.safeString(order, 'order_status')),
|
|
1920
|
+
'symbol': symbol,
|
|
1921
|
+
'type': type,
|
|
1922
|
+
'timeInForce': undefined,
|
|
1923
|
+
'postOnly': undefined,
|
|
1924
|
+
'side': side,
|
|
1925
|
+
'price': price,
|
|
1926
|
+
'stopPrice': triggerPrice,
|
|
1927
|
+
'triggerPrice': triggerPrice,
|
|
1928
|
+
'cost': cost,
|
|
1929
|
+
'amount': amount,
|
|
1930
|
+
'filled': undefined,
|
|
1931
|
+
'remaining': undefined,
|
|
1932
|
+
'average': undefined,
|
|
1933
|
+
'trades': transactions,
|
|
1934
|
+
'fee': undefined,
|
|
1935
|
+
'info': order,
|
|
1936
|
+
}, market);
|
|
1937
|
+
}
|
|
1938
|
+
async fetchCanceledOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
1939
|
+
/**
|
|
1940
|
+
* @method
|
|
1941
|
+
* @name exmo#fetchCanceledOrders
|
|
1942
|
+
* @description fetches information on multiple canceled orders made by the user
|
|
1943
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#1d2524dd-ae6d-403a-a067-77b50d13fbe5 // margin
|
|
1944
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#a51be1d0-af5f-44e4-99d7-f7b04c6067d0 // spot canceled orders
|
|
1945
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
1946
|
+
* @param {int} [since] timestamp in ms of the earliest order, default is undefined
|
|
1947
|
+
* @param {int} [limit] max number of orders to return, default is undefined
|
|
1948
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
1949
|
+
* @param {string} [params.marginMode] set to "isolated" for margin orders
|
|
1950
|
+
* @returns {object} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
1951
|
+
*/
|
|
1952
|
+
await this.loadMarkets();
|
|
1953
|
+
let marginMode = undefined;
|
|
1954
|
+
[marginMode, params] = this.handleMarginModeAndParams('fetchOrders', params);
|
|
1955
|
+
if (marginMode === 'cross') {
|
|
1956
|
+
throw new errors.BadRequest(this.id + ' only supports isolated margin');
|
|
1957
|
+
}
|
|
1958
|
+
if (limit === undefined) {
|
|
1959
|
+
limit = 100;
|
|
1960
|
+
}
|
|
1961
|
+
const isSpot = (marginMode !== 'isolated');
|
|
1962
|
+
if (symbol !== undefined) {
|
|
1963
|
+
const marketInner = this.market(symbol);
|
|
1964
|
+
symbol = marketInner['symbol'];
|
|
1965
|
+
}
|
|
1966
|
+
const request = {
|
|
1967
|
+
'limit': limit,
|
|
1968
|
+
};
|
|
1969
|
+
request['offset'] = (since !== undefined) ? limit : 0;
|
|
1970
|
+
request['limit'] = limit;
|
|
1971
|
+
let market = undefined;
|
|
1972
|
+
if (symbol !== undefined) {
|
|
1973
|
+
market = this.market(symbol);
|
|
1974
|
+
}
|
|
1975
|
+
let response = undefined;
|
|
1976
|
+
if (isSpot) {
|
|
1977
|
+
response = await this.privatePostUserCancelledOrders(this.extend(request, params));
|
|
1978
|
+
//
|
|
1979
|
+
// [
|
|
1980
|
+
// {
|
|
1981
|
+
// "order_id": "27056153840",
|
|
1982
|
+
// "client_id": "0",
|
|
1983
|
+
// "created": "1653428646",
|
|
1984
|
+
// "type": "buy",
|
|
1985
|
+
// "pair": "BTC_USDT",
|
|
1986
|
+
// "quantity": "0.1",
|
|
1987
|
+
// "price": "10",
|
|
1988
|
+
// "amount": "1"
|
|
1989
|
+
// }
|
|
1990
|
+
// ]
|
|
1991
|
+
//
|
|
1992
|
+
params = this.extend(params, {
|
|
1993
|
+
'status': 'canceled',
|
|
1994
|
+
});
|
|
1995
|
+
return this.parseOrders(response, market, since, limit, params);
|
|
1996
|
+
}
|
|
1997
|
+
else {
|
|
1998
|
+
const responseSwap = await this.privatePostMarginUserOrderHistory(this.extend(request, params));
|
|
1999
|
+
//
|
|
2000
|
+
// {
|
|
2001
|
+
// "items": [
|
|
2002
|
+
// {
|
|
2003
|
+
// "event_id": "692862104574106858",
|
|
2004
|
+
// "event_time": "1694116400173489405",
|
|
2005
|
+
// "event_type": "OrderCancelStarted",
|
|
2006
|
+
// "order_id": "692862104561289319",
|
|
2007
|
+
// "order_type": "stop_limit_sell",
|
|
2008
|
+
// "order_status": "cancel_started",
|
|
2009
|
+
// "trade_id": "0",
|
|
2010
|
+
// "trade_type":"",
|
|
2011
|
+
// "trade_quantity": "0",
|
|
2012
|
+
// "trade_price": "0",
|
|
2013
|
+
// "pair": "ADA_USDT",
|
|
2014
|
+
// "quantity": "12",
|
|
2015
|
+
// "price": "0.23",
|
|
2016
|
+
// "stop_price": "0.22",
|
|
2017
|
+
// "distance": "0"
|
|
2018
|
+
// }
|
|
2019
|
+
// ...
|
|
2020
|
+
// ]
|
|
2021
|
+
// }
|
|
2022
|
+
//
|
|
2023
|
+
const items = this.safeValue(responseSwap, 'items');
|
|
2024
|
+
const orders = this.parseOrders(items, market, since, limit, params);
|
|
2025
|
+
const result = [];
|
|
2026
|
+
for (let i = 0; i < orders.length; i++) {
|
|
2027
|
+
const order = orders[i];
|
|
2028
|
+
if (order['status'] === 'canceled') {
|
|
2029
|
+
result.push(order);
|
|
2030
|
+
}
|
|
2031
|
+
}
|
|
2032
|
+
return result;
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
async editOrder(id, symbol, type, side, amount = undefined, price = undefined, params = {}) {
|
|
2036
|
+
/**
|
|
2037
|
+
* @method
|
|
2038
|
+
* @name exmo#editOrder
|
|
2039
|
+
* @description *margin only* edit a trade order
|
|
2040
|
+
* @see https://documenter.getpostman.com/view/10287440/SzYXWKPi#f27ee040-c75f-4b59-b608-d05bd45b7899 // margin
|
|
2041
|
+
* @param {string} id order id
|
|
2042
|
+
* @param {string} symbol unified CCXT market symbol
|
|
2043
|
+
* @param {string} type not used by exmo editOrder
|
|
2044
|
+
* @param {string} side not used by exmo editOrder
|
|
2045
|
+
* @param {float} [amount] how much of the currency you want to trade in units of the base currency
|
|
2046
|
+
* @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
|
2047
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2048
|
+
* @param {float} [params.triggerPrice] stop price for stop-market and stop-limit orders
|
|
2049
|
+
* @param {string} params.marginMode must be set to isolated
|
|
2050
|
+
*
|
|
2051
|
+
* EXCHANGE SPECIFIC PARAMETERS
|
|
2052
|
+
* @param {int} [params.distance] distance for trailing stop orders
|
|
2053
|
+
* @param {int} [params.expire] expiration timestamp in UTC timezone for the order. order will not be expired if expire is 0
|
|
2054
|
+
* @param {string} [params.comment] optional comment for order. up to 50 latin symbols, whitespaces, underscores
|
|
2055
|
+
* @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
2056
|
+
*/
|
|
2057
|
+
await this.loadMarkets();
|
|
2058
|
+
const market = this.market(symbol);
|
|
2059
|
+
let marginMode = undefined;
|
|
2060
|
+
[marginMode, params] = this.handleMarginModeAndParams('editOrder', params);
|
|
2061
|
+
if (marginMode !== 'isolated') {
|
|
2062
|
+
throw new errors.BadRequest(this.id + ' editOrder() can only be used for isolated margin orders');
|
|
2063
|
+
}
|
|
2064
|
+
const triggerPrice = this.safeNumberN(params, ['triggerPrice', 'stopPrice', 'stop_price']);
|
|
2065
|
+
params = this.omit(params, ['triggerPrice', 'stopPrice']);
|
|
2066
|
+
const request = {
|
|
2067
|
+
'order_id': id, // id of the open order
|
|
2068
|
+
};
|
|
2069
|
+
if (amount !== undefined) {
|
|
2070
|
+
request['quantity'] = amount;
|
|
2071
|
+
}
|
|
2072
|
+
if (price !== undefined) {
|
|
2073
|
+
request['price'] = this.priceToPrecision(market['symbol'], price);
|
|
2074
|
+
}
|
|
2075
|
+
if (triggerPrice !== undefined) {
|
|
2076
|
+
request['stop_price'] = this.priceToPrecision(market['symbol'], triggerPrice);
|
|
2077
|
+
}
|
|
2078
|
+
const response = await this.privatePostMarginUserOrderUpdate(this.extend(request, params));
|
|
2079
|
+
return this.parseOrder(response);
|
|
2080
|
+
}
|
|
2081
|
+
async fetchDepositAddress(code, params = {}) {
|
|
2082
|
+
/**
|
|
2083
|
+
* @method
|
|
2084
|
+
* @name exmo#fetchDepositAddress
|
|
2085
|
+
* @description fetch the deposit address for a currency associated with this account
|
|
2086
|
+
* @param {string} code unified currency code
|
|
2087
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2088
|
+
* @returns {object} an [address structure]{@link https://docs.ccxt.com/#/?id=address-structure}
|
|
2089
|
+
*/
|
|
2090
|
+
await this.loadMarkets();
|
|
2091
|
+
const response = await this.privatePostDepositAddress(params);
|
|
2092
|
+
//
|
|
2093
|
+
// {
|
|
2094
|
+
// "TRX":"TBnwrf4ZdoYXE3C8L2KMs7YPSL3fg6q6V9",
|
|
2095
|
+
// "USDTTRC20":"TBnwrf4ZdoYXE3C8L2KMs7YPSL3fg6q6V9"
|
|
2096
|
+
// }
|
|
2097
|
+
//
|
|
2098
|
+
const depositAddress = this.safeString(response, code);
|
|
2099
|
+
let address = undefined;
|
|
2100
|
+
let tag = undefined;
|
|
2101
|
+
if (depositAddress) {
|
|
2102
|
+
const addressAndTag = depositAddress.split(',');
|
|
2103
|
+
address = addressAndTag[0];
|
|
2104
|
+
const numParts = addressAndTag.length;
|
|
2105
|
+
if (numParts > 1) {
|
|
2106
|
+
tag = addressAndTag[1];
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2109
|
+
this.checkAddress(address);
|
|
2110
|
+
return {
|
|
2111
|
+
'currency': code,
|
|
2112
|
+
'address': address,
|
|
2113
|
+
'tag': tag,
|
|
2114
|
+
'network': undefined,
|
|
2115
|
+
'info': response,
|
|
2116
|
+
};
|
|
2117
|
+
}
|
|
2118
|
+
getMarketFromTrades(trades) {
|
|
2119
|
+
const tradesBySymbol = this.indexBy(trades, 'pair');
|
|
2120
|
+
const symbols = Object.keys(tradesBySymbol);
|
|
2121
|
+
const numSymbols = symbols.length;
|
|
2122
|
+
if (numSymbols === 1) {
|
|
2123
|
+
return this.markets[symbols[0]];
|
|
2124
|
+
}
|
|
2125
|
+
return undefined;
|
|
2126
|
+
}
|
|
2127
|
+
async withdraw(code, amount, address, tag = undefined, params = {}) {
|
|
2128
|
+
/**
|
|
2129
|
+
* @method
|
|
2130
|
+
* @name exmo#withdraw
|
|
2131
|
+
* @description make a withdrawal
|
|
2132
|
+
* @param {string} code unified currency code
|
|
2133
|
+
* @param {float} amount the amount to withdraw
|
|
2134
|
+
* @param {string} address the address to withdraw to
|
|
2135
|
+
* @param {string} tag
|
|
2136
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2137
|
+
* @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
2138
|
+
*/
|
|
2139
|
+
[tag, params] = this.handleWithdrawTagAndParams(tag, params);
|
|
2140
|
+
await this.loadMarkets();
|
|
2141
|
+
const currency = this.currency(code);
|
|
2142
|
+
const request = {
|
|
2143
|
+
'amount': amount,
|
|
2144
|
+
'currency': currency['id'],
|
|
2145
|
+
'address': address,
|
|
2146
|
+
};
|
|
2147
|
+
if (tag !== undefined) {
|
|
2148
|
+
request['invoice'] = tag;
|
|
2149
|
+
}
|
|
2150
|
+
const networks = this.safeValue(this.options, 'networks', {});
|
|
2151
|
+
let network = this.safeStringUpper(params, 'network'); // this line allows the user to specify either ERC20 or ETH
|
|
2152
|
+
network = this.safeString(networks, network, network); // handle ERC20>ETH alias
|
|
2153
|
+
if (network !== undefined) {
|
|
2154
|
+
request['transport'] = network;
|
|
2155
|
+
params = this.omit(params, 'network');
|
|
2156
|
+
}
|
|
2157
|
+
const response = await this.privatePostWithdrawCrypt(this.extend(request, params));
|
|
2158
|
+
return this.parseTransaction(response, currency);
|
|
2159
|
+
}
|
|
2160
|
+
parseTransactionStatus(status) {
|
|
2161
|
+
const statuses = {
|
|
2162
|
+
'transferred': 'ok',
|
|
2163
|
+
'paid': 'ok',
|
|
2164
|
+
'pending': 'pending',
|
|
2165
|
+
'processing': 'pending',
|
|
2166
|
+
'verifying': 'pending',
|
|
2167
|
+
};
|
|
2168
|
+
return this.safeString(statuses, status, status);
|
|
2169
|
+
}
|
|
2170
|
+
parseTransaction(transaction, currency = undefined) {
|
|
2171
|
+
//
|
|
2172
|
+
// fetchDepositsWithdrawals
|
|
2173
|
+
//
|
|
2174
|
+
// {
|
|
2175
|
+
// "dt": 1461841192,
|
|
2176
|
+
// "type": "deposit",
|
|
2177
|
+
// "curr": "RUB",
|
|
2178
|
+
// "status": "processing",
|
|
2179
|
+
// "provider": "Qiwi (LA) [12345]",
|
|
2180
|
+
// "amount": "1",
|
|
2181
|
+
// "account": "",
|
|
2182
|
+
// "txid": "ec46f784ad976fd7f7539089d1a129fe46...",
|
|
2183
|
+
// }
|
|
2184
|
+
//
|
|
2185
|
+
// fetchWithdrawals
|
|
2186
|
+
//
|
|
2187
|
+
// {
|
|
2188
|
+
// "operation_id": 47412538520634344,
|
|
2189
|
+
// "created": 1573760013,
|
|
2190
|
+
// "updated": 1573760013,
|
|
2191
|
+
// "type": "withdraw",
|
|
2192
|
+
// "currency": "DOGE",
|
|
2193
|
+
// "status": "Paid",
|
|
2194
|
+
// "amount": "300",
|
|
2195
|
+
// "provider": "DOGE",
|
|
2196
|
+
// "commission": "0",
|
|
2197
|
+
// "account": "DOGE: DBVy8pF1f8yxaCVEHqHeR7kkcHecLQ8nRS",
|
|
2198
|
+
// "order_id": 69670170,
|
|
2199
|
+
// "provider_type": "crypto",
|
|
2200
|
+
// "crypto_address": "DBVy8pF1f8yxaCVEHqHeR7kkcHecLQ8nRS",
|
|
2201
|
+
// "card_number": "",
|
|
2202
|
+
// "wallet_address": "",
|
|
2203
|
+
// "email": "",
|
|
2204
|
+
// "phone": "",
|
|
2205
|
+
// "extra": {
|
|
2206
|
+
// "txid": "f2b66259ae1580f371d38dd27e31a23fff8c04122b65ee3ab5a3f612d579c792",
|
|
2207
|
+
// "confirmations": null,
|
|
2208
|
+
// "excode": "",
|
|
2209
|
+
// "invoice": ""
|
|
2210
|
+
// },
|
|
2211
|
+
// "error": ""
|
|
2212
|
+
// }
|
|
2213
|
+
//
|
|
2214
|
+
// withdraw
|
|
2215
|
+
//
|
|
2216
|
+
// {
|
|
2217
|
+
// "result": true,
|
|
2218
|
+
// "error": "",
|
|
2219
|
+
// "task_id": 11775077
|
|
2220
|
+
// }
|
|
2221
|
+
//
|
|
2222
|
+
const timestamp = this.safeTimestamp2(transaction, 'dt', 'created');
|
|
2223
|
+
let amountString = this.safeString(transaction, 'amount');
|
|
2224
|
+
if (amountString !== undefined) {
|
|
2225
|
+
amountString = Precise["default"].stringAbs(amountString);
|
|
2226
|
+
}
|
|
2227
|
+
let txid = this.safeString(transaction, 'txid');
|
|
2228
|
+
if (txid === undefined) {
|
|
2229
|
+
const extra = this.safeValue(transaction, 'extra', {});
|
|
2230
|
+
const extraTxid = this.safeString(extra, 'txid');
|
|
2231
|
+
if (extraTxid !== '') {
|
|
2232
|
+
txid = extraTxid;
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
const type = this.safeString(transaction, 'type');
|
|
2236
|
+
const currencyId = this.safeString2(transaction, 'curr', 'currency');
|
|
2237
|
+
const code = this.safeCurrencyCode(currencyId, currency);
|
|
2238
|
+
let address = undefined;
|
|
2239
|
+
let comment = undefined;
|
|
2240
|
+
const account = this.safeString(transaction, 'account');
|
|
2241
|
+
if (type === 'deposit') {
|
|
2242
|
+
comment = account;
|
|
2243
|
+
}
|
|
2244
|
+
else if (type === 'withdrawal') {
|
|
2245
|
+
address = account;
|
|
2246
|
+
if (address !== undefined) {
|
|
2247
|
+
const parts = address.split(':');
|
|
2248
|
+
const numParts = parts.length;
|
|
2249
|
+
if (numParts === 2) {
|
|
2250
|
+
address = this.safeString(parts, 1);
|
|
2251
|
+
address = address.replace(' ', '');
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
}
|
|
2255
|
+
const fee = {
|
|
2256
|
+
'currency': undefined,
|
|
2257
|
+
'cost': undefined,
|
|
2258
|
+
'rate': undefined,
|
|
2259
|
+
};
|
|
2260
|
+
// fixed funding fees only (for now)
|
|
2261
|
+
if (!this.fees['transaction']['percentage']) {
|
|
2262
|
+
const key = (type === 'withdrawal') ? 'withdraw' : 'deposit';
|
|
2263
|
+
let feeCost = this.safeString(transaction, 'commission');
|
|
2264
|
+
if (feeCost === undefined) {
|
|
2265
|
+
const transactionFees = this.safeValue(this.options, 'transactionFees', {});
|
|
2266
|
+
const codeFees = this.safeValue(transactionFees, code, {});
|
|
2267
|
+
feeCost = this.safeString(codeFees, key);
|
|
2268
|
+
}
|
|
2269
|
+
// users don't pay for cashbacks, no fees for that
|
|
2270
|
+
const provider = this.safeString(transaction, 'provider');
|
|
2271
|
+
if (provider === 'cashback') {
|
|
2272
|
+
feeCost = '0';
|
|
2273
|
+
}
|
|
2274
|
+
if (feeCost !== undefined) {
|
|
2275
|
+
// withdrawal amount includes the fee
|
|
2276
|
+
if (type === 'withdrawal') {
|
|
2277
|
+
amountString = Precise["default"].stringSub(amountString, feeCost);
|
|
2278
|
+
}
|
|
2279
|
+
fee['cost'] = this.parseNumber(feeCost);
|
|
2280
|
+
fee['currency'] = code;
|
|
2281
|
+
}
|
|
2282
|
+
}
|
|
2283
|
+
return {
|
|
2284
|
+
'info': transaction,
|
|
2285
|
+
'id': this.safeString2(transaction, 'order_id', 'task_id'),
|
|
2286
|
+
'txid': txid,
|
|
2287
|
+
'type': type,
|
|
2288
|
+
'currency': code,
|
|
2289
|
+
'network': this.safeString(transaction, 'provider'),
|
|
2290
|
+
'amount': this.parseNumber(amountString),
|
|
2291
|
+
'status': this.parseTransactionStatus(this.safeStringLower(transaction, 'status')),
|
|
2292
|
+
'timestamp': timestamp,
|
|
2293
|
+
'datetime': this.iso8601(timestamp),
|
|
2294
|
+
'address': address,
|
|
2295
|
+
'addressFrom': undefined,
|
|
2296
|
+
'addressTo': address,
|
|
2297
|
+
'tag': undefined,
|
|
2298
|
+
'tagFrom': undefined,
|
|
2299
|
+
'tagTo': undefined,
|
|
2300
|
+
'updated': this.safeTimestamp(transaction, 'updated'),
|
|
2301
|
+
'comment': comment,
|
|
2302
|
+
'internal': undefined,
|
|
2303
|
+
'fee': fee,
|
|
2304
|
+
};
|
|
2305
|
+
}
|
|
2306
|
+
async fetchDepositsWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
2307
|
+
/**
|
|
2308
|
+
* @method
|
|
2309
|
+
* @name exmo#fetchDepositsWithdrawals
|
|
2310
|
+
* @description fetch history of deposits and withdrawals
|
|
2311
|
+
* @param {string} [code] unified currency code for the currency of the deposit/withdrawals, default is undefined
|
|
2312
|
+
* @param {int} [since] timestamp in ms of the earliest deposit/withdrawal, default is undefined
|
|
2313
|
+
* @param {int} [limit] max number of deposit/withdrawals to return, default is undefined
|
|
2314
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2315
|
+
* @returns {object} a list of [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
2316
|
+
*/
|
|
2317
|
+
await this.loadMarkets();
|
|
2318
|
+
const request = {};
|
|
2319
|
+
if (since !== undefined) {
|
|
2320
|
+
request['date'] = this.parseToInt(since / 1000);
|
|
2321
|
+
}
|
|
2322
|
+
let currency = undefined;
|
|
2323
|
+
if (code !== undefined) {
|
|
2324
|
+
currency = this.currency(code);
|
|
2325
|
+
}
|
|
2326
|
+
const response = await this.privatePostWalletHistory(this.extend(request, params));
|
|
2327
|
+
//
|
|
2328
|
+
// {
|
|
2329
|
+
// "result": true,
|
|
2330
|
+
// "error": "",
|
|
2331
|
+
// "begin": "1493942400",
|
|
2332
|
+
// "end": "1494028800",
|
|
2333
|
+
// "history": [
|
|
2334
|
+
// {
|
|
2335
|
+
// "dt": 1461841192,
|
|
2336
|
+
// "type": "deposit",
|
|
2337
|
+
// "curr": "RUB",
|
|
2338
|
+
// "status": "processing",
|
|
2339
|
+
// "provider": "Qiwi (LA) [12345]",
|
|
2340
|
+
// "amount": "1",
|
|
2341
|
+
// "account": "",
|
|
2342
|
+
// "txid": "ec46f784ad976fd7f7539089d1a129fe46...",
|
|
2343
|
+
// },
|
|
2344
|
+
// {
|
|
2345
|
+
// "dt": 1463414785,
|
|
2346
|
+
// "type": "withdrawal",
|
|
2347
|
+
// "curr": "USD",
|
|
2348
|
+
// "status": "paid",
|
|
2349
|
+
// "provider": "EXCODE",
|
|
2350
|
+
// "amount": "-1",
|
|
2351
|
+
// "account": "EX-CODE_19371_USDda...",
|
|
2352
|
+
// "txid": "",
|
|
2353
|
+
// },
|
|
2354
|
+
// ],
|
|
2355
|
+
// }
|
|
2356
|
+
//
|
|
2357
|
+
return this.parseTransactions(response['history'], currency, since, limit);
|
|
2358
|
+
}
|
|
2359
|
+
async fetchWithdrawals(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
2360
|
+
/**
|
|
2361
|
+
* @method
|
|
2362
|
+
* @name exmo#fetchWithdrawals
|
|
2363
|
+
* @description fetch all withdrawals made from an account
|
|
2364
|
+
* @param {string} code unified currency code
|
|
2365
|
+
* @param {int} [since] the earliest time in ms to fetch withdrawals for
|
|
2366
|
+
* @param {int} [limit] the maximum number of withdrawals structures to retrieve
|
|
2367
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2368
|
+
* @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
2369
|
+
*/
|
|
2370
|
+
await this.loadMarkets();
|
|
2371
|
+
let currency = undefined;
|
|
2372
|
+
const request = {
|
|
2373
|
+
'type': 'withdraw',
|
|
2374
|
+
};
|
|
2375
|
+
if (limit !== undefined) {
|
|
2376
|
+
request['limit'] = limit; // default: 100, maximum: 100
|
|
2377
|
+
}
|
|
2378
|
+
if (code !== undefined) {
|
|
2379
|
+
currency = this.currency(code);
|
|
2380
|
+
request['currency'] = currency['id'];
|
|
2381
|
+
}
|
|
2382
|
+
const response = await this.privatePostWalletOperations(this.extend(request, params));
|
|
2383
|
+
//
|
|
2384
|
+
// {
|
|
2385
|
+
// "items": [
|
|
2386
|
+
// {
|
|
2387
|
+
// "operation_id": 47412538520634344,
|
|
2388
|
+
// "created": 1573760013,
|
|
2389
|
+
// "updated": 1573760013,
|
|
2390
|
+
// "type": "withdraw",
|
|
2391
|
+
// "currency": "DOGE",
|
|
2392
|
+
// "status": "Paid",
|
|
2393
|
+
// "amount": "300",
|
|
2394
|
+
// "provider": "DOGE",
|
|
2395
|
+
// "commission": "0",
|
|
2396
|
+
// "account": "DOGE: DBVy8pF1f8yxaCVEHqHeR7kkcHecLQ8nRS",
|
|
2397
|
+
// "order_id": 69670170,
|
|
2398
|
+
// "extra": {
|
|
2399
|
+
// "txid": "f2b66259ae1580f371d38dd27e31a23fff8c04122b65ee3ab5a3f612d579c792",
|
|
2400
|
+
// "excode": "",
|
|
2401
|
+
// "invoice": ""
|
|
2402
|
+
// },
|
|
2403
|
+
// "error": ""
|
|
2404
|
+
// },
|
|
2405
|
+
// ],
|
|
2406
|
+
// "count": 23
|
|
2407
|
+
// }
|
|
2408
|
+
//
|
|
2409
|
+
const items = this.safeValue(response, 'items', []);
|
|
2410
|
+
return this.parseTransactions(items, currency, since, limit);
|
|
2411
|
+
}
|
|
2412
|
+
async fetchWithdrawal(id, code = undefined, params = {}) {
|
|
2413
|
+
/**
|
|
2414
|
+
* @method
|
|
2415
|
+
* @name exmo#fetchWithdrawal
|
|
2416
|
+
* @description fetch data on a currency withdrawal via the withdrawal id
|
|
2417
|
+
* @param {string} id withdrawal id
|
|
2418
|
+
* @param {string} code unified currency code of the currency withdrawn, default is undefined
|
|
2419
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2420
|
+
* @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
2421
|
+
*/
|
|
2422
|
+
await this.loadMarkets();
|
|
2423
|
+
let currency = undefined;
|
|
2424
|
+
const request = {
|
|
2425
|
+
'order_id': id,
|
|
2426
|
+
'type': 'withdraw',
|
|
2427
|
+
};
|
|
2428
|
+
if (code !== undefined) {
|
|
2429
|
+
currency = this.currency(code);
|
|
2430
|
+
request['currency'] = currency['id'];
|
|
2431
|
+
}
|
|
2432
|
+
const response = await this.privatePostWalletOperations(this.extend(request, params));
|
|
2433
|
+
//
|
|
2434
|
+
// {
|
|
2435
|
+
// "items": [
|
|
2436
|
+
// {
|
|
2437
|
+
// "operation_id": 47412538520634344,
|
|
2438
|
+
// "created": 1573760013,
|
|
2439
|
+
// "updated": 1573760013,
|
|
2440
|
+
// "type": "deposit",
|
|
2441
|
+
// "currency": "DOGE",
|
|
2442
|
+
// "status": "Paid",
|
|
2443
|
+
// "amount": "300",
|
|
2444
|
+
// "provider": "DOGE",
|
|
2445
|
+
// "commission": "0",
|
|
2446
|
+
// "account": "DOGE: DBVy8pF1f8yxaCVEHqHeR7kkcHecLQ8nRS",
|
|
2447
|
+
// "order_id": 69670170,
|
|
2448
|
+
// "extra": {
|
|
2449
|
+
// "txid": "f2b66259ae1580f371d38dd27e31a23fff8c04122b65ee3ab5a3f612d579c792",
|
|
2450
|
+
// "excode": "",
|
|
2451
|
+
// "invoice": ""
|
|
2452
|
+
// },
|
|
2453
|
+
// "error": ""
|
|
2454
|
+
// },
|
|
2455
|
+
// ],
|
|
2456
|
+
// "count": 23
|
|
2457
|
+
// }
|
|
2458
|
+
//
|
|
2459
|
+
const items = this.safeValue(response, 'items', []);
|
|
2460
|
+
const first = this.safeValue(items, 0, {});
|
|
2461
|
+
return this.parseTransaction(first, currency);
|
|
2462
|
+
}
|
|
2463
|
+
async fetchDeposit(id = undefined, code = undefined, params = {}) {
|
|
2464
|
+
/**
|
|
2465
|
+
* @method
|
|
2466
|
+
* @name exmo#fetchDeposit
|
|
2467
|
+
* @description fetch information on a deposit
|
|
2468
|
+
* @param {string} id deposit id
|
|
2469
|
+
* @param {string} code unified currency code, default is undefined
|
|
2470
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2471
|
+
* @returns {object} a [transaction structure]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
2472
|
+
*/
|
|
2473
|
+
await this.loadMarkets();
|
|
2474
|
+
let currency = undefined;
|
|
2475
|
+
const request = {
|
|
2476
|
+
'order_id': id,
|
|
2477
|
+
'type': 'deposit',
|
|
2478
|
+
};
|
|
2479
|
+
if (code !== undefined) {
|
|
2480
|
+
currency = this.currency(code);
|
|
2481
|
+
request['currency'] = currency['id'];
|
|
2482
|
+
}
|
|
2483
|
+
const response = await this.privatePostWalletOperations(this.extend(request, params));
|
|
2484
|
+
//
|
|
2485
|
+
// {
|
|
2486
|
+
// "items": [
|
|
2487
|
+
// {
|
|
2488
|
+
// "operation_id": 47412538520634344,
|
|
2489
|
+
// "created": 1573760013,
|
|
2490
|
+
// "updated": 1573760013,
|
|
2491
|
+
// "type": "deposit",
|
|
2492
|
+
// "currency": "DOGE",
|
|
2493
|
+
// "status": "Paid",
|
|
2494
|
+
// "amount": "300",
|
|
2495
|
+
// "provider": "DOGE",
|
|
2496
|
+
// "commission": "0",
|
|
2497
|
+
// "account": "DOGE: DBVy8pF1f8yxaCVEHqHeR7kkcHecLQ8nRS",
|
|
2498
|
+
// "order_id": 69670170,
|
|
2499
|
+
// "extra": {
|
|
2500
|
+
// "txid": "f2b66259ae1580f371d38dd27e31a23fff8c04122b65ee3ab5a3f612d579c792",
|
|
2501
|
+
// "excode": "",
|
|
2502
|
+
// "invoice": ""
|
|
2503
|
+
// },
|
|
2504
|
+
// "error": ""
|
|
2505
|
+
// },
|
|
2506
|
+
// ],
|
|
2507
|
+
// "count": 23
|
|
2508
|
+
// }
|
|
2509
|
+
//
|
|
2510
|
+
const items = this.safeValue(response, 'items', []);
|
|
2511
|
+
const first = this.safeValue(items, 0, {});
|
|
2512
|
+
return this.parseTransaction(first, currency);
|
|
2513
|
+
}
|
|
2514
|
+
async fetchDeposits(code = undefined, since = undefined, limit = undefined, params = {}) {
|
|
2515
|
+
/**
|
|
2516
|
+
* @method
|
|
2517
|
+
* @name exmo#fetchDeposits
|
|
2518
|
+
* @description fetch all deposits made to an account
|
|
2519
|
+
* @param {string} code unified currency code
|
|
2520
|
+
* @param {int} [since] the earliest time in ms to fetch deposits for
|
|
2521
|
+
* @param {int} [limit] the maximum number of deposits structures to retrieve
|
|
2522
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
2523
|
+
* @returns {object[]} a list of [transaction structures]{@link https://docs.ccxt.com/#/?id=transaction-structure}
|
|
2524
|
+
*/
|
|
2525
|
+
await this.loadMarkets();
|
|
2526
|
+
let currency = undefined;
|
|
2527
|
+
const request = {
|
|
2528
|
+
'type': 'deposit',
|
|
2529
|
+
};
|
|
2530
|
+
if (limit !== undefined) {
|
|
2531
|
+
request['limit'] = limit; // default: 100, maximum: 100
|
|
2532
|
+
}
|
|
2533
|
+
if (code !== undefined) {
|
|
2534
|
+
currency = this.currency(code);
|
|
2535
|
+
request['currency'] = currency['id'];
|
|
2536
|
+
}
|
|
2537
|
+
const response = await this.privatePostWalletOperations(this.extend(request, params));
|
|
2538
|
+
//
|
|
2539
|
+
// {
|
|
2540
|
+
// "items": [
|
|
2541
|
+
// {
|
|
2542
|
+
// "operation_id": 47412538520634344,
|
|
2543
|
+
// "created": 1573760013,
|
|
2544
|
+
// "updated": 1573760013,
|
|
2545
|
+
// "type": "deposit",
|
|
2546
|
+
// "currency": "DOGE",
|
|
2547
|
+
// "status": "Paid",
|
|
2548
|
+
// "amount": "300",
|
|
2549
|
+
// "provider": "DOGE",
|
|
2550
|
+
// "commission": "0",
|
|
2551
|
+
// "account": "DOGE: DBVy8pF1f8yxaCVEHqHeR7kkcHecLQ8nRS",
|
|
2552
|
+
// "order_id": 69670170,
|
|
2553
|
+
// "extra": {
|
|
2554
|
+
// "txid": "f2b66259ae1580f371d38dd27e31a23fff8c04122b65ee3ab5a3f612d579c792",
|
|
2555
|
+
// "excode": "",
|
|
2556
|
+
// "invoice": ""
|
|
2557
|
+
// },
|
|
2558
|
+
// "error": ""
|
|
2559
|
+
// },
|
|
2560
|
+
// ],
|
|
2561
|
+
// "count": 23
|
|
2562
|
+
// }
|
|
2563
|
+
//
|
|
2564
|
+
const items = this.safeValue(response, 'items', []);
|
|
2565
|
+
return this.parseTransactions(items, currency, since, limit);
|
|
2566
|
+
}
|
|
2567
|
+
sign(path, api = 'public', method = 'GET', params = {}, headers = undefined, body = undefined) {
|
|
2568
|
+
let url = this.urls['api'][api] + '/';
|
|
2569
|
+
if (api !== 'web') {
|
|
2570
|
+
url += this.version + '/';
|
|
2571
|
+
}
|
|
2572
|
+
url += path;
|
|
2573
|
+
if ((api === 'public') || (api === 'web')) {
|
|
2574
|
+
if (Object.keys(params).length) {
|
|
2575
|
+
url += '?' + this.urlencode(params);
|
|
2576
|
+
}
|
|
2577
|
+
}
|
|
2578
|
+
else if (api === 'private') {
|
|
2579
|
+
this.checkRequiredCredentials();
|
|
2580
|
+
const nonce = this.nonce();
|
|
2581
|
+
body = this.urlencode(this.extend({ 'nonce': nonce }, params));
|
|
2582
|
+
headers = {
|
|
2583
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
2584
|
+
'Key': this.apiKey,
|
|
2585
|
+
'Sign': this.hmac(this.encode(body), this.encode(this.secret), sha512.sha512),
|
|
2586
|
+
};
|
|
2587
|
+
}
|
|
2588
|
+
return { 'url': url, 'method': method, 'body': body, 'headers': headers };
|
|
2589
|
+
}
|
|
2590
|
+
nonce() {
|
|
2591
|
+
return this.milliseconds();
|
|
2592
|
+
}
|
|
2593
|
+
handleErrors(httpCode, reason, url, method, headers, body, response, requestHeaders, requestBody) {
|
|
2594
|
+
if (response === undefined) {
|
|
2595
|
+
return undefined; // fallback to default error handler
|
|
2596
|
+
}
|
|
2597
|
+
if (('error' in response) && !('result' in response)) {
|
|
2598
|
+
// error: {
|
|
2599
|
+
// "code": "140434",
|
|
2600
|
+
// "msg": "Your margin balance is not sufficient to place the order for '5 TON'. Please top up your margin wallet by "2.5 USDT"."
|
|
2601
|
+
// }
|
|
2602
|
+
//
|
|
2603
|
+
const errorCode = this.safeValue(response, 'error', {});
|
|
2604
|
+
const messageError = this.safeString(errorCode, 'msg');
|
|
2605
|
+
const code = this.safeString(errorCode, 'code');
|
|
2606
|
+
const feedback = this.id + ' ' + body;
|
|
2607
|
+
this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
|
|
2608
|
+
this.throwBroadlyMatchedException(this.exceptions['broad'], messageError, feedback);
|
|
2609
|
+
throw new errors.ExchangeError(feedback);
|
|
2610
|
+
}
|
|
2611
|
+
if (('result' in response) || ('errmsg' in response)) {
|
|
2612
|
+
//
|
|
2613
|
+
// {"result":false,"error":"Error 50052: Insufficient funds"}
|
|
2614
|
+
// {"s":"error","errmsg":"strconv.ParseInt: parsing \"\": invalid syntax"}
|
|
2615
|
+
//
|
|
2616
|
+
let success = this.safeValue(response, 'result', false);
|
|
2617
|
+
if (typeof success === 'string') {
|
|
2618
|
+
if ((success === 'true') || (success === '1')) {
|
|
2619
|
+
success = true;
|
|
2620
|
+
}
|
|
2621
|
+
else {
|
|
2622
|
+
success = false;
|
|
2623
|
+
}
|
|
2624
|
+
}
|
|
2625
|
+
if (!success) {
|
|
2626
|
+
let code = undefined;
|
|
2627
|
+
const message = this.safeString2(response, 'error', 'errmsg');
|
|
2628
|
+
const errorParts = message.split(':');
|
|
2629
|
+
const numParts = errorParts.length;
|
|
2630
|
+
if (numParts > 1) {
|
|
2631
|
+
const errorSubParts = errorParts[0].split(' ');
|
|
2632
|
+
const numSubParts = errorSubParts.length;
|
|
2633
|
+
code = (numSubParts > 1) ? errorSubParts[1] : errorSubParts[0];
|
|
2634
|
+
}
|
|
2635
|
+
const feedback = this.id + ' ' + body;
|
|
2636
|
+
this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
|
|
2637
|
+
this.throwBroadlyMatchedException(this.exceptions['broad'], message, feedback);
|
|
2638
|
+
throw new errors.ExchangeError(feedback);
|
|
2639
|
+
}
|
|
2640
|
+
}
|
|
2641
|
+
return undefined;
|
|
2642
|
+
}
|
|
2643
|
+
}
|
|
2644
|
+
|
|
2645
|
+
module.exports = exmo;
|